active software documentation using soul and intensive
DESCRIPTION
TRANSCRIPT
Département d’Ingénierie Informatique - Université catholique de Louvain
Active Software Documentation usingSoul and IntensiVE
Johan Brichau, Kim Mens,
Coen De Roover, Andy Kellens,
Roel Wuyts
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Documenting Software...
2
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Documenting Software...
2
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Documenting Software...
2
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Documenting Software...
2
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Documenting Software...
2
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Discovering and Documenting
RegularitiesArchitectureIdiomsPatternsConventions
BugsBad smells
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
3
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
3
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} ); frame.setUndecorated(true);JLabel label = new JLabel("."); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!");
}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
3
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} ); frame.setUndecorated(true);JLabel label = new JLabel("."); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!");
}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency?
Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
4
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} ); frame.setUndecorated(true);JLabel label = new JLabel("."); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!");
}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
4
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} ); frame.setUndecorated(true);JLabel label = new JLabel("."); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!");
}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Evolving Software...
4
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} ); frame.setUndecorated(true);JLabel label = new JLabel("."); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!");
}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
?Software Documentation
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Erosion Problem
• Architectural drift and design decay• Documentation of source code becomes inconsistent
• Original design structure and architecture is eroded
5
time
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); }
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address);
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year
source code v1.0
documentationv1.0
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Erosion Problem
• Architectural drift and design decay• Documentation of source code becomes inconsistent
• Original design structure and architecture is eroded
5
time
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); }
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address);
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year
source code v1.0
documentationv1.0
documentationv1.0
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); }
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address);
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year
source code v2.0
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1;
}
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Active Software Documentation
6
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Discovering, documenting and enforcing
RegularitiesArchitectureIdiomsPatternsConventions
BugsBad smells
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Software Documentation
Active Software Documentation
6
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
Discovering, documenting and enforcing
RegularitiesArchitectureIdiomsPatternsConventions
BugsBad smells
Code Queries Causal
Link
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
Small programs vs. Large projects
7
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
Small programs vs. Large projects
7
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
import java.io.*;import java.util.zip.*;
/** * Command line program to copy a file to another directory. * @author Marco Schmidt */public class CopyFile { // constant values for the override option public static final int OVERWRITE_ALWAYS = 1; public static final int OVERWRITE_NEVER = 2; public static final int OVERWRITE_ASK = 3;
// program options initialized to default values private static int bufferSize = 4 * 1024; private static boolean clock = true; private static boolean copyOriginalTimestamp = true; private static boolean verify = true; private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile) throws IOException { InputStream in = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile); long millis = System.currentTimeMillis(); CRC32 checksum = null; if (verify) { checksum = new CRC32(); checksum.reset(); } byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { if (verify) { checksum.update(buffer, 0, bytesRead); } out.write(buffer, 0, bytesRead); } out.close(); in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } if (verify) { return new Long(checksum.getValue()); } else { return null; } }
public static Long createChecksum(File file) throws IOException { long millis = System.currentTimeMillis(); InputStream in = new FileInputStream(file); CRC32 checksum = new CRC32(); checksum.reset(); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { checksum.update(buffer, 0, bytesRead); } in.close(); if (clock) { millis = System.currentTimeMillis() - millis; System.out.println("Second(s): " + (millis/1000L)); } return new Long(checksum.getValue()); }
/** * Determine if data is to be copied to given file. * Take into consideration override option and * ask user in case file exists and override option is ask. * @param file File object for potential destination file * @return true if data is to be copied to file, false if not */ public static boolean doCopy(File file) { boolean exists = file.exists(); if (override == OVERWRITE_ALWAYS || !exists) { return true; } else if (override == OVERWRITE_NEVER) { return false; } else if (override == OVERWRITE_ASK) { return readYesNoFromStandardInput("File exists. " + "Overwrite (y/n)?"); } else { throw new InternalError("Program error. Invalid " + "value for override: " + override); } }
public static void main(String[] args) throws IOException { // make sure there are exactly two arguments if (args.length != 2) { System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME"); System.exit(1); } // make sure the source file is indeed a readable file File srcFile = new File(args[0]); if (!srcFile.isFile() || !srcFile.canRead()) { System.err.println("Not a readable file: " + srcFile.getName()); System.exit(1); } // make sure the second argument is a directory File destDir = new File(args[1]); if (!destDir.isDirectory()) { System.err.println("Not a directory: " + destDir.getName()); System.exit(1); } // create File object for destination file File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option if (!doCopy(destFile)) { return; }
// copy file, optionally creating a checksum Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification if (copyOriginalTimestamp) { if (!destFile.setLastModified(srcFile.lastModified())) { System.err.println("Error: Could not set " + "timestamp of copied file."); } }
// optionally verify file if (verify) { System.out.print("Verifying destination file..."); Long checksumDest = createChecksum(destFile); if (checksumSrc.equals(checksumDest)) { System.out.println(" OK, files are equal."); } else { System.out.println(" Error: Checksums differ."); } } }
/** * Print a message to standard output and read lines from * standard input until yes or no (y or n) is entered. * @param message informative text to be answered by user * @return user answer, true for yes, false for no. */ public static boolean readYesNoFromStandardInput(String message) { System.out.println(message); String line; BufferedReader in = new BufferedReader(new InputStreamReader( System.in)); Boolean answer = null; try { while ((line = in.readLine()) != null) { line = line.toLowerCase(); if ("y".equals(line) || "yes".equals(line)) { answer = Boolean.TRUE; break; } else if ("n".equals(line) || "no".equals(line)) { answer = Boolean.FALSE; break; } else { System.out.println("Could not understand answer (\"" + line + "\"). Please use y for yes or n for no."); } } if (answer == null) { throw new IOException("Unexpected end of input from stdin."); } in.close(); return answer.booleanValue(); } catch (IOException ioe) { throw new InternalError( "Cannot read from stdin or write to stdout."); } }}
*/public class FileDownload { public static void download(String address, String localFileName) { OutputStream out = null; URLConnection conn = null; InputStream in = null; try { URL url = new URL(address); out = new BufferedOutputStream( new FileOutputStream(localFileName)); conn = url.openConnection(); in = conn.getInputStream(); byte[] buffer = new byte[1024]; int numRead; long numWritten = 0; while ((numRead = in.read(buffer)) != -1) { out.write(buffer, 0, numRead); numWritten += numRead; } System.out.println(localFileName + "\t" + numWritten); } catch (Exception exception) { exception.printStackTrace(); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException ioe) { } } }
public static void download(String address) { int lastSlashIndex = address.lastIndexOf('/'); if (lastSlashIndex >= 0 && lastSlashIndex < address.length() - 1) { download(address, address.substring(lastSlashIndex + 1)); } else { System.err.println("Could not figure out local file name for " + address); } }
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { download(args[i]); } }}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
import java.io.*;
import java.util.zip.*;
/** * Command line program to copy a file to another directory.
* @author Marco Schmidt
*/public class CopyFile {
// constant values for the override option
public static final int OVERWRITE_ALWAYS = 1;
public static final int OVERWRITE_NEVER = 2;
public static final int OVERWRITE_ASK = 3;
// program options initialized to default values
private static int bufferSize = 4 * 1024;
private static boolean clock = true;
private static boolean copyOriginalTimestamp = true;
private static boolean verify = true;
private static int override = OVERWRITE_ASK;
public static Long copyFile(File srcFile, File destFile)
throws IOException {
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
long millis = System.currentTimeMillis();
CRC32 checksum = null;
if (verify) {
checksum = new CRC32();
checksum.reset();
}
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
if (verify) {
checksum.update(buffer, 0, bytesRead);
}
out.write(buffer, 0, bytesRead);
}
out.close();
in.close();
if (clock) {
millis = System.currentTimeMillis() - millis;
System.out.println("Second(s): " + (millis/1000L));
}
if (verify) {
return new Long(checksum.getValue());
} else {
return null;
}
}
public static Long createChecksum(File file) throws IOException {
long millis = System.currentTimeMillis();
InputStream in = new FileInputStream(file);
CRC32 checksum = new CRC32();
checksum.reset();
byte[] buffer = new byte[bufferSize];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
checksum.update(buffer, 0, bytesRead);
}
in.close();
if (clock) {
millis = System.currentTimeMillis() - millis;
System.out.println("Second(s): " + (millis/1000L));
}
return new Long(checksum.getValue());
}
/**
* Determine if data is to be copied to given file.
* Take into consideration override option and
* ask user in case file exists and override option is ask.
* @param file File object for potential destination file
* @return true if data is to be copied to file, false if not
*/
public static boolean doCopy(File file) {
boolean exists = file.exists();
if (override == OVERWRITE_ALWAYS || !exists) {
return true;
} else
if (override == OVERWRITE_NEVER) {
return false;
} else
if (override == OVERWRITE_ASK) {
return readYesNoFromStandardInput("File exists. " +
"Overwrite (y/n)?");
} else {
throw new InternalError("Program error. Invalid " +
"value for override: " + override);
}
}
public static void main(String[] args) throws IOException {
// make sure there are exactly two arguments
if (args.length != 2) {
System.err.println("Usage: CopyFile SRC-FILE-NAME DEST-DIR-NAME");
System.exit(1);
}
// make sure the source file is indeed a readable file
File srcFile = new File(args[0]);
if (!srcFile.isFile() || !srcFile.canRead()) {
System.err.println("Not a readable file: " + srcFile.getName());
System.exit(1);
}
// make sure the second argument is a directory
File destDir = new File(args[1]);
if (!destDir.isDirectory()) {
System.err.println("Not a directory: " + destDir.getName());
System.exit(1);
}
// create File object for destination file
File destFile = new File(destDir, srcFile.getName());
// check if copying is desired given overwrite option
if (!doCopy(destFile)) {
return;
}
// copy file, optionally creating a checksum
Long checksumSrc = copyFile(srcFile, destFile);
// copy timestamp of last modification
if (copyOriginalTimestamp) {
if (!destFile.setLastModified(srcFile.lastModified())) {
System.err.println("Error: Could not set " +
"timestamp of copied file.");
}
}
// optionally verify file
if (verify) {
System.out.print("Verifying destination file...");
Long checksumDest = createChecksum(destFile);
if (checksumSrc.equals(checksumDest)) {
System.out.println(" OK, files are equal.");
} else {
System.out.println(" Error: Checksums differ.");
}
}
}
/**
* Print a message to standard output and read lines from
* standard input until yes or no (y or n) is entered.
* @param message informative text to be answered by user
* @return user answer, true for yes, false for no.
*/
public static boolean readYesNoFromStandardInput(String message) {
System.out.println(message);
String line;
BufferedReader in = new BufferedReader(new InputStreamReader(
System.in));
Boolean answer = null;
try
{
while ((line = in.readLine()) != null) {
line = line.toLowerCase();
if ("y".equals(line) || "yes".equals(line)) {
answer = Boolean.TRUE;
break;
}
else
if ("n".equals(line) || "no".equals(line)) {
answer = Boolean.FALSE;
break;
}
else
{
System.out.println("Could not understand answer (\"" +
line + "\"). Please use y for yes or n for no.");
}
}
if (answer == null) {
throw new IOException("Unexpected end of input from stdin.");
}
in.close();
return answer.booleanValue();
}
catch (IOException ioe)
{
throw new InternalError(
"Cannot read from stdin or write to stdout.");
}
}
}
*/
public class HappyNewYear implements Runnable
{
private static NumberFormat formatter = NumberFormat.getInstance();
private JFrame frame;
private JLabel label;
private long newYearMillis;
private String message;
public HappyNewYear(JFrame frame, JLabel label)
{
// store argument GUI elements
this.frame = frame;
this.label = label;
// compute beginning of next year
Calendar cal = new GregorianCalendar();
int nextYear = cal.get(Calendar.YEAR) + 1;
cal.set(Calendar.YEAR, nextYear);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
newYearMillis = cal.getTime().getTime();
// prepare a message
message = "Happy " + nextYear + "!";
}
public static int determineFontSize(JFrame frame,
int componentWidth, String fontName, int fontStyle,
String text)
{
int fontSize = componentWidth * 2 / text.length();
Font font = new Font(fontName, fontStyle, fontSize);
FontMetrics fontMetrics = frame.getGraphics().
getFontMetrics(font);
int stringWidth = fontMetrics.stringWidth(text);
return (int)(fontSize * 0.95 *
componentWidth / stringWidth);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent event) {}
public void keyReleased(KeyEvent event) {
if (event.getKeyChar() == KeyEvent.VK_ESCAPE)
{
System.exit(0);
}
}
public void keyTyped(KeyEvent event) {}
}
);
frame.setUndecorated(true);
JLabel label = new JLabel(".");
label.setBackground(Color.BLACK);
label.setForeground(Color.WHITE);
label.setOpaque(true);
label.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(label);
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().setFullScreenWindow(frame);
final int fontStyle = Font.BOLD;
final String fontName = "SansSerif";
int fontSizeNumber = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, formatter.format(88888888));
int fontSizeText = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, "Happy 8888!");
label.setFont(new Font(fontName, fontStyle,
Math.min(fontSizeNumber, fontSizeText)));
new HappyNewYear(frame, label).run();
}
public void run()
{
boolean newYear = false;
do
{
long time = System.currentTimeMillis();
long remaining = (newYearMillis - time) / 1000L;
String output;
if (remaining < 1)
{
// new year!
newYear = true;
output = message;
}
else
{
// make a String from the number of seconds
output = formatter.format(remaining);
}
label.setText(output);
try
{
Thread.sleep(1000);
}
}
*/
public class HappyNewYear implements Runnable
{
private static NumberFormat formatter = NumberFormat.getInstance();
private JFrame frame;
private JLabel label;
private long newYearMillis;
private String message;
public HappyNewYear(JFrame frame, JLabel label)
{
// store argument GUI elements
this.frame = frame;
this.label = label;
// compute beginning of next year
Calendar cal = new GregorianCalendar();
int nextYear = cal.get(Calendar.YEAR) + 1;
cal.set(Calendar.YEAR, nextYear);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
newYearMillis = cal.getTime().getTime();
// prepare a message
message = "Happy " + nextYear + "!";
}
public static int determineFontSize(JFrame frame,
int componentWidth, String fontName, int fontStyle,
String text)
{
int fontSize = componentWidth * 2 / text.length();
Font font = new Font(fontName, fontStyle, fontSize);
FontMetrics fontMetrics = frame.getGraphics().
getFontMetrics(font);
int stringWidth = fontMetrics.stringWidth(text);
return (int)(fontSize * 0.95 *
componentWidth / stringWidth);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent event) {}
public void keyReleased(KeyEvent event) {
if (event.getKeyChar() == KeyEvent.VK_ESCAPE)
{
System.exit(0);
}
}
public void keyTyped(KeyEvent event) {}
}
);
frame.setUndecorated(true);
JLabel label = new JLabel(".");
label.setBackground(Color.BLACK);
label.setForeground(Color.WHITE);
label.setOpaque(true);
label.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(label);
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().setFullScreenWindow(frame);
final int fontStyle = Font.BOLD;
final String fontName = "SansSerif";
int fontSizeNumber = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, formatter.format(88888888));
int fontSizeText = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, "Happy 8888!");
label.setFont(new Font(fontName, fontStyle,
Math.min(fontSizeNumber, fontSizeText)));
new HappyNewYear(frame, label).run();
}
public void run()
{
boolean newYear = false;
do
{
long time = System.currentTimeMillis();
long remaining = (newYearMillis - time) / 1000L;
String output;
if (remaining < 1)
{
// new year!
newYear = true;
output = message;
}
else
{
// make a String from the number of seconds
output = formatter.format(remaining);
}
label.setText(output);
try
{
Thread.sleep(1000);
}
}
*/
public
class
Happy
NewYea
r impl
ements
Runna
ble
{
privat
e stat
ic Num
berFor
mat fo
rmatte
r = Nu
mberFo
rmat.g
etInst
ance()
;
privat
e JFra
me fra
me;
privat
e JLab
el lab
el;
privat
e long
newYe
arMill
is;
privat
e Stri
ng mes
sage;
public
Happy
NewYea
r(JFra
me fra
me, JL
abel l
abel)
{
// sto
re arg
ument
GUI el
ements
this.f
rame =
frame
;
this.l
abel =
label
;
// com
pute b
eginni
ng of
next y
ear
Calend
ar cal
= new
Grego
rianCa
lendar
();
int ne
xtYear
= cal
.get(C
alenda
r.YEAR
) + 1;
cal.se
t(Cale
ndar.Y
EAR, n
extYea
r);
cal.se
t(Cale
ndar.M
ONTH,
Calend
ar.JAN
UARY);
cal.se
t(Cale
ndar.D
AY_OF_
MONTH,
1);
cal.se
t(Cale
ndar.H
OUR_OF
_DAY,
0);
cal.se
t(Cale
ndar.M
INUTE,
0);
cal.se
t(Cale
ndar.S
ECOND,
0);
newYea
rMilli
s = ca
l.getT
ime().
getTim
e();
// pre
pare a
messa
ge
messag
e = "H
appy "
+ nex
tYear
+ "!";
}
public
stati
c int
determ
ineFon
tSize(
JFrame
frame
,
int co
mponen
tWidth
, Stri
ng fon
tName,
int f
ontSty
le,
String
text)
{
int fo
ntSize
= com
ponent
Width
* 2 /
text.l
ength(
);
Font f
ont =
new Fo
nt(fon
tName,
fontS
tyle,
fontSi
ze);
FontMe
trics
fontMe
trics
= fram
e.getG
raphic
s().
getFon
tMetri
cs(fon
t);
int st
ringWi
dth =
fontMe
trics.
string
Width(
text);
return
(int)
(fontS
ize *
0.95 *
compon
entWid
th / s
tringW
idth);
}
public
stati
c void
main(
String
[] arg
s)
{
JFrame
frame
= new
JFram
e();
frame.
addKey
Listen
er(new
KeyLi
stener
()
{
public
void
keyPre
ssed(K
eyEven
t even
t) {}
public
void
keyRel
eased(
KeyEve
nt eve
nt) {
if (ev
ent.ge
tKeyCh
ar() =
= KeyE
vent.V
K_ESCA
PE)
{
System
.exit(
0);
}
}
public
void
keyTyp
ed(Key
Event
event)
{}
}
);
frame.
setUnd
ecorat
ed(tru
e);
JLabel
label
= new
JLabe
l(".")
;
label.
setBac
kgroun
d(Colo
r.BLAC
K);
label.
setFor
egroun
d(Colo
r.WHIT
E);
label.
setOpa
que(tr
ue);
label.
setHor
izonta
lAlign
ment(S
wingCo
nstant
s.CENT
ER);
frame.
getCon
tentPa
ne().a
dd(lab
el);
Graphi
csEnvi
ronmen
t.getL
ocalGr
aphics
Enviro
nment(
).
getDef
aultSc
reenDe
vice()
.setFu
llScre
enWind
ow(fra
me);
final
int fo
ntStyl
e = Fo
nt.BOL
D;
final
String
fontN
ame =
"SansS
erif";
int fo
ntSize
Number
= det
ermine
FontSi
ze(fra
me,
Toolki
t.getD
efault
Toolki
t().ge
tScree
nSize(
).widt
h,
fontNa
me, fo
ntStyl
e, for
matter
.forma
t(8888
8888))
;
int fo
ntSize
Text =
deter
mineFo
ntSize
(frame
,
Toolki
t.getD
efault
Toolki
t().ge
tScree
nSize(
).widt
h,
fontNa
me, fo
ntStyl
e, "Ha
ppy 88
88!");
label.
setFon
t(new
Font(f
ontNam
e, fon
tStyle
,
Math.m
in(fon
tSizeN
umber,
fontS
izeTex
t)));
new Ha
ppyNew
Year(f
rame,
label)
.run()
;
}
pu
blic v
oid ru
n()
{
boolea
n newY
ear =
false;
do
{
long t
ime =
System
.curre
ntTime
Millis
();
long r
emaini
ng = (
newYea
rMilli
s - ti
me) /
1000L;
String
outpu
t;
if (re
mainin
g < 1)
{
// new
year!
newYea
r = tr
ue;
output
= mes
sage;
}
else
{
// mak
e a St
ring f
rom th
e numb
er of
second
s
output
= for
matter
.forma
t(rema
ining)
;
}
label.
setTex
t(outp
ut);
try
{
Thread
.sleep
(1000)
;
}
}
*/public class HappyNewYear implements Runnable
{ private static NumberFormat formatter = NumberFormat.getInstance(); private JFrame frame; private JLabel label; private long newYearMillis; private String message;
public HappyNewYear(JFrame frame, JLabel label) { // store argument GUI elements this.frame = frame; this.label = label; // compute beginning of next year Calendar cal = new GregorianCalendar(); int nextYear = cal.get(Calendar.YEAR) + 1; cal.set(Calendar.YEAR, nextYear); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); newYearMillis = cal.getTime().getTime(); // prepare a message message = "Happy " + nextYear + "!"; }
public static int determineFontSize(JFrame frame, int componentWidth, String fontName, int fontStyle, String text) { int fontSize = componentWidth * 2 / text.length(); Font font = new Font(fontName, fontStyle, fontSize); FontMetrics fontMetrics = frame.getGraphics(). getFontMetrics(font); int stringWidth = fontMetrics.stringWidth(text); return (int)(fontSize * 0.95 * componentWidth / stringWidth); }
public static void main(String[] args) { JFrame frame = new JFrame(); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent event) {} public void keyReleased(KeyEvent event) { if (event.getKeyChar() == KeyEvent.VK_ESCAPE) { System.exit(0); } } public void keyTyped(KeyEvent event) {} } ); frame.setUndecorated(true); JLabel label = new JLabel("."); label.setBackground(Color.BLACK); label.setForeground(Color.WHITE); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); frame.getContentPane().add(label); GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(frame); final int fontStyle = Font.BOLD; final String fontName = "SansSerif"; int fontSizeNumber = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, formatter.format(88888888)); int fontSizeText = determineFontSize(frame, Toolkit.getDefaultToolkit().getScreenSize().width, fontName, fontStyle, "Happy 8888!"); label.setFont(new Font(fontName, fontStyle, Math.min(fontSizeNumber, fontSizeText))); new HappyNewYear(frame, label).run(); }
public void run() { boolean newYear = false; do { long time = System.currentTimeMillis(); long remaining = (newYearMillis - time) / 1000L; String output; if (remaining < 1) { // new year! newYear = true; output = message; } else { // make a String from the number of seconds output = formatter.format(remaining); } label.setText(output); try { Thread.sleep(1000); }}
*/
public class HappyNewYear implements Runnable
{
private static NumberFormat formatter = NumberFormat.getInstance();
private JFrame frame;
private JLabel label;
private long newYearMillis;
private String message;
public HappyNewYear(JFrame frame, JLabel label)
{
// store argument GUI elements
this.frame = frame;
this.label = label;
// compute beginning of next year
Calendar cal = new GregorianCalendar();
int nextYear = cal.get(Calendar.YEAR) + 1;
cal.set(Calendar.YEAR, nextYear);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
newYearMillis = cal.getTime().getTime();
// prepare a message
message = "Happy " + nextYear + "!";
}
public static int determineFontSize(JFrame frame,
int componentWidth, String fontName, int fontStyle,
String text)
{
int fontSize = componentWidth * 2 / text.length();
Font font = new Font(fontName, fontStyle, fontSize);
FontMetrics fontMetrics = frame.getGraphics().
getFontMetrics(font);
int stringWidth = fontMetrics.stringWidth(text);
return (int)(fontSize * 0.95 *
componentWidth / stringWidth);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent event) {}
public void keyReleased(KeyEvent event) {
if (event.getKeyChar() == KeyEvent.VK_ESCAPE)
{
System.exit(0);
}
}
public void keyTyped(KeyEvent event) {}
}
);
frame.setUndecorated(true);
JLabel label = new JLabel(".");
label.setBackground(Color.BLACK);
label.setForeground(Color.WHITE);
label.setOpaque(true);
label.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(label);
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().setFullScreenWindow(frame);
final int fontStyle = Font.BOLD;
final String fontName = "SansSerif";
int fontSizeNumber = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, formatter.format(88888888));
int fontSizeText = determineFontSize(frame,
Toolkit.getDefaultToolkit().getScreenSize().width,
fontName, fontStyle, "Happy 8888!");
label.setFont(new Font(fontName, fontStyle,
Math.min(fontSizeNumber, fontSizeText)));
new HappyNewYear(frame, label).run();
}
public void run()
{
boolean newYear = false;
do
{
long time = System.currentTimeMillis();
long remaining = (newYearMillis - time) / 1000L;
String output;
if (remaining < 1)
{
// new year!
newYear = true;
output = message;
}
else
{
// make a String from the number of seconds
output = formatter.format(remaining);
}
label.setText(output);
try
{
Thread.sleep(1000);
}
}
Manual exploration & documentation
do not scale
Tool Support Needed
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Querying Code
8
- (Simple) name-based searches- Mostly textual matching
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Querying Code
8
- (Simple) name-based searches- Mostly textual matching
- Name-based searches - Limited use of structural reflection
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Querying Code
8
- (Simple) name-based searches- Mostly textual matching
- Name-based searches - Limited use of structural reflection
JTL
- Full query language - Based on reflection, metaprogramming, analysis, etc..
PQL
ASTLOG .......... .....
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
• Smalltalk Open Unification Language• Prolog-based query language
• Hybrid (Prolog + Smalltalk)
• Inter-language Reflection
• Metalanguage over Smalltalk base language
• Execute queries over programs
• using full structural and computational reflection
• using combination of logic and imperative paradigms
SOUL
9
• Declarative Reasoning about the Structure of Object-Oriented Systems, Roel Wuyts. Proc. TOOLS USA 1998, pp. 112-124. IEEE Computer Society Press, 1998.
• Co-evolution of Object-Oriented Software Design and Implementation. Theo D'Hondt, Kris De Volder, Kim Mens & Roel Wuyts, Proc. SACT 2000. Kluwer Academic Publishers, 2000.
• A Logic Meta-Programming Approach to Support the Co-Evolution of Object-Oriented Design and Implementation. Roel Wuyts. PhD thesis, Dept. of Computer Science, VUB, 2001.
• Supporting software development through declaratively codified programming patterns. Kim Mens, Isabel Michiels & Roel Wuyts. Journal on Expert Systems with Applications, Volume 23, Issue 4, November 2002, Page 405, Elsevier.
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Meta Programming
10
SQL query
Expenses Database
Queries
“Standard” Program
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Meta Programming
10
SQL query
Expenses Database
Queries
“Standard” Program
Compiler compiles programsJavaDoc generates documentation for programs...
Soul query
Software Database
Queries
Meta Program
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Meta Programming
10
SQL query
Expenses Database
Queries
“Standard” Program
Compiler compiles programsJavaDoc generates documentation for programs...
Soul query
Software Database
Queries
Meta Program
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Meta Programming
10
SQL query
Expenses Database
Queries
“Standard” Program
Compiler compiles programsJavaDoc generates documentation for programs...
Soul query
Software Database
Queries
Meta Program
Meta Program Programs
Works with
Program Data
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
Logic fact
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
Predicate
Logic fact
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
SOUL Constant
Predicate
Logic fact
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
SOUL Constant
Predicate
Logic fact
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
11
Family Structure
parentOf(Joe,Mark).parentOf(Joe,Sarah).parentOf(Mark,Kevin).parentOf(Christine,Kevin).parentOf(Sarah,Sophie).parentOf(Frank,Sophie).
SOUL representation of the
family Structure
SOUL Constant
Predicate
Logic fact
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
if parentOf(?parent,?child)
?child -> Mark?parent -> Joe
?child -> Sarah?parent -> Joe
...
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
grandparentOf(?grandparent,?grandchild) ifparentOf(?grandparent,?parent),parentOf(?parent,?grandchild).
couple(?personA,?personB) ifparentOf(?personA,?child),parentOf(?personB,?child)
SOUL deduction rules
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
grandparentOf(?grandparent,?grandchild) ifparentOf(?grandparent,?parent),parentOf(?parent,?grandchild).
couple(?personA,?personB) ifparentOf(?personA,?child),parentOf(?personB,?child)
SOUL deduction rules
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin logic rule
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
grandparentOf(?grandparent,?grandchild) ifparentOf(?grandparent,?parent),parentOf(?parent,?grandchild).
couple(?personA,?personB) ifparentOf(?personA,?child),parentOf(?personB,?child)
SOUL deduction rules
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin logic rule SOUL variable
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
grandparentOf(?grandparent,?grandchild) ifparentOf(?grandparent,?parent),parentOf(?parent,?grandchild).
couple(?personA,?personB) ifparentOf(?personA,?child),parentOf(?personB,?child)
SOUL deduction rules
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin logic rule SOUL variable
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
12
Deduced Family Structure
grandparentOf(?grandparent,?grandchild) ifparentOf(?grandparent,?parent),parentOf(?parent,?grandchild).
couple(?personA,?personB) ifparentOf(?personA,?child),parentOf(?personB,?child)
SOUL deduction rules
Joe
Mark
parent of
Kevin
parent of
Christine
parent of
Sarah
parent of
Frank
parent of
Sophie
parent of
grandparent ofgrandparent of
couplecouple
cousin logic rule SOUL variable
if grandparentOf(?grandparent,?child)
?grandparent -> Joe?child -> Kevin
?grandparent -> Joe?child -> Sophie
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
13
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
13
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
class(Node).class(StatementList).subclassOf(StatementList,CompositeNode).variableInClass(name,Node).methodInClass(getChildren,CompositeNode).....
Representational mapping
Reification
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
13
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
class(Node).class(StatementList).subclassOf(StatementList,CompositeNode).variableInClass(name,Node).methodInClass(getChildren,CompositeNode).....
Representational mapping
Reification
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
13
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
class(Node).class(StatementList).subclassOf(StatementList,CompositeNode).variableInClass(name,Node).methodInClass(getChildren,CompositeNode).....
Representational mapping
Reification
if class(?x)
-- all Smalltalk classes --
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reification
14
The SOUL results contain the *real* classes.i.e.: the Smalltalk class values
idem for methods, packages, namespaces, etc...
Representational mapping is computed using a logic rule that uses Smalltalk reflection
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
15
DeducedSoftware structure
classInHierarchyOf(?class,?superclass) if subclassOf(?class,?superclass).classInHierarchyOf(?class,?superclass) if subclassOf(?interclass,?superclass),
classInHierarchyOf(?class,?interclass).
SOUL logic reasoning
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
15
DeducedSoftware structure
classInHierarchyOf(?class,?superclass) if subclassOf(?class,?superclass).classInHierarchyOf(?class,?superclass) if subclassOf(?interclass,?superclass),
classInHierarchyOf(?class,?interclass).
SOUL logic reasoning
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
logic alternatives
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
15
DeducedSoftware structure
classInHierarchyOf(?class,?superclass) if subclassOf(?class,?superclass).classInHierarchyOf(?class,?superclass) if subclassOf(?interclass,?superclass),
classInHierarchyOf(?class,?interclass).
SOUL logic reasoning
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
logic alternatives
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
15
DeducedSoftware structure
classInHierarchyOf(?class,?superclass) if subclassOf(?class,?superclass).classInHierarchyOf(?class,?superclass) if subclassOf(?interclass,?superclass),
classInHierarchyOf(?class,?interclass).
SOUL logic reasoning
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode
logic alternatives
if classInHierarchyOf(?class,[ApplicationModel])
-- all subclasses of ApplicationModel --
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Prolog-based query language
16
• Unification:• powerful pattern matching• multi-way predicates
• Recursion: detection of...• ...recursive patterns in code• ...composite structures in code
• Declarative:• focuses on ‘what’ instead of ‘how’ • multiple alternative descriptions of same pattern
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Smalltalk vs Soul
17
result := Collection new.Smalltalk allClasses do:[:class | class selectors do:[:selector | | method | method := class compiledMethodAt: selector. class instVarNames do:[:name | (method writesField:(class instVarIndexFor: name))
ifTrue:[result add: method]]]].^result
if methodInClass(?method,?class), methodWithAssignment(?method, assign(?field,?value)), instanceVariableInClass(?field,?class)
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reasoning over OO programs
18
someMethod
SuperClass
SubClass
<<references>>
Finding a hard coupling between a class and its subclass:
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reasoning over OO programs
18
if class(?c),methodInClass(?method,?c),methodReferencesClass(?method,?s),classBelow(?s,?c)
someMethod
SuperClass
SubClass
<<references>>
Finding a hard coupling between a class and its subclass:
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
19
someMethod
SuperClass
SubClass
<<references>>
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
19
if class(?c),methodInClass(?method,?c),methodReferencesClass(?method,?s),classBelow(?s,?c)
someMethod
SuperClass
SubClass
<<references>>
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
19
if class(?c),methodInClass(?method,?c),methodReferencesClass(?method,?s),classBelow(?s,?c)
someMethod
SuperClass
SubClass
<<references>>
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
19
if class(?c),methodInClass(?method,?c),methodReferencesClass(?method,?s),classBelow(?s,?c)
someMethod
SuperClass
SubClass
<<references>>
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
19
if class(?c),methodInClass(?method,?c),methodReferencesClass(?method,?s),classBelow(?s,?c)
someMethod
SuperClass
SubClass
<<references>>
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding subclass dependencies
20
Queries through 7734 classes and 72962 methods in 44 seconds to find 360 solutions
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reasoning over OO programs
21
Finding the “Composite” design pattern
compositePattern(?comp,?composite,?msg) if compositeStructure(?comp,?composite), compositeAggregation(?comp,?composite,?msg)
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding the Composite Pattern
22
Finding the “Composite” structure
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding the Composite Pattern
22
compositeStructure(?comp,?composite) if class(?comp),classInHierarchyOf(?composite,?comp)
Finding the “Composite” structure
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding the Composite Pattern
23
compositeAggregation(?comp,?composite,?msg) if classesImplementCommonSelector(?comp,?composite,?msg),methodWithNameInClass(?method,?msg,?composite),statementOfMethod(?statement,?method),iterationStatementWithBlock(?statement,?iterationBlock),blockIteratesMessage(?iterationBlock,?msg)
Finding the “Aggregation” structure
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding the Composite Pattern
23
compositeAggregation(?comp,?composite,?msg) if classesImplementCommonSelector(?comp,?composite,?msg),methodWithNameInClass(?method,?msg,?composite),statementOfMethod(?statement,?method),iterationStatementWithBlock(?statement,?iterationBlock),blockIteratesMessage(?iterationBlock,?msg)
Finding the “Aggregation” structure
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Finding the Composite Pattern
24
Some of the results in the Smalltalk image:
Queries through 7734 classes and 72962 methods in 13 minutes to find 81 solutions
(Soul is about 10x slower than commercial Prologs)
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Teaser: Visual Query Language
25
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Hybrid Language
26
if classInHierarchyOf(?class,[ApplicationModel])
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Hybrid Language
26
if classInHierarchyOf(?class,[ApplicationModel])
The SOUL results contain the *real* classes.i.e.: the Smalltalk class values
Smalltalk expression evaluating to the class ApplicationModel
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Hybrid Language
26
if classInHierarchyOf(?class,[ApplicationModel])
className(?class,?name) if class(?class), equals(?name,[?class name]).smallerThan(?x,?y) if [?x < ?y]
The SOUL results contain the *real* classes.i.e.: the Smalltalk class values
Smalltalk expression evaluating to the class ApplicationModel
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Hybrid Language
26
if classInHierarchyOf(?class,[ApplicationModel])
className(?class,?name) if class(?class), equals(?name,[?class name]).smallerThan(?x,?y) if [?x < ?y]
The SOUL results contain the *real* classes.i.e.: the Smalltalk class values
Smalltalk expression evaluating to the class ApplicationModel
Smalltalk expression- resulting object is unified with ?name
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Hybrid Language
26
if classInHierarchyOf(?class,[ApplicationModel])
className(?class,?name) if class(?class), equals(?name,[?class name]).smallerThan(?x,?y) if [?x < ?y]
The SOUL results contain the *real* classes.i.e.: the Smalltalk class values
Smalltalk expression evaluating to the class ApplicationModel
Smalltalk expression- resulting object is unified with ?name
Smalltalk expression- evaluates to true or false
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reification revisited
27
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode Reification
class(?class) ifmember(?class,[Smalltalk allClasses]).
methodInClass(?method,?class) ifmember(?method,[?class selectors
collect:[:sel | ?class compiledMethodAt: sel]])
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reification revisited
27
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode Reification
class(?class) ifmember(?class,[Smalltalk allClasses]).
methodInClass(?method,?class) ifmember(?method,[?class selectors
collect:[:sel | ?class compiledMethodAt: sel]])
a collection of all classes
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Reification revisited
27
Software structure
printOn:
nameNode
getChildrenprintOn:
children
CompositeNode
...
...Statement
...
...Expression
printOn:
message
MessageSend
printOn:
varVariableRef
printOn:
StatementList
printOn:
sourceheader
MethodNode Reification
class(?class) ifmember(?class,[Smalltalk allClasses]).
methodInClass(?method,?class) ifmember(?method,[?class selectors
collect:[:sel | ?class compiledMethodAt: sel]])
a collection of all classes
a collection of all methods on a class
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: hybrid language
28
• Reification of *real* Smalltalk meta-objects:
• Meta-objects are normal objects• can reason about ‘structure’ and ‘runtime values’
• Open Unification
• Causal link
• Passing of results to other (Smalltalk) tools
• Full reflection inherited from Smalltalk
• Uniform approach for reasoning about any object, including runtime values
Advantages:
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL
29
• Smalltalk Open Unification Language• Queries on-line over a codebase
• Structural as well as computational reflection
• Supports reasoning over code in a declarative style
SOULInference Engine
Logic Programs
Smalltalk Reflection
Smalltalk image
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL
29
• Smalltalk Open Unification Language• Queries on-line over a codebase
• Structural as well as computational reflection
• Supports reasoning over code in a declarative style
SOULInference Engine
Logic Programs
Smalltalk Reflection
Smalltalk image
JavaConnect + JDT
Eclipse workspace
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL
29
• Smalltalk Open Unification Language• Queries on-line over a codebase
• Structural as well as computational reflection
• Supports reasoning over code in a declarative style
SOULInference Engine
Logic Programs
Smalltalk Reflection
Smalltalk image
JavaConnect + JDT
Eclipse workspace
JavaConnect + Soot
Soot Analysis
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Open Unification
30
cfr. ‘Open Implementations’
• Define precise unification semantics for entities
• Hiding ‘imperative matching’ process
• For example:
• Unification of objects based on object identity
• Unification of parsetrees via pattern matching
• Unification of variables based on points-to analysis
• etc....
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Open Unification
31
Unification protocol implemented by parsetree items:
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Open Unification
31
Unification protocol implemented by parsetree items:
Objects match based on object identity
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Open Unification
31
Unification protocol implemented by parsetree items:
Objects match based on object identity
Method (objects) match if source code is identical
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
SOUL: Open Unification
31
Unification protocol implemented by parsetree items:
Objects match based on object identity
Method (objects) match if source code is identical
Enhanced parsetree matching:
Expression match based on points-to-analysis
Method bodies match based on control-flow analysis
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Demonstration
32
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Active Software Documentation
33
Software Documentation
Calls to database
- After state change- Follows DB protocol (open + (read/write) + close)
Factory Methods
- Must be used to create objects consistently
Coding Convention
- Classes implementing events: ‘*Event’- Must be adhered for consistency
• Enforce:• Adhering to DB protocol• Using Factory methods• Coding conventions
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Intensional Views
34
I want to be able to express additional semantic constraints on my programs. An example would be « the GUI module should never call the database directly ». What I lack is a tool that allows me to specify such constraints (like « the GUI shouldn't call the DB ») as queries so that I am able to check to see where in the code base this ad-hoc rule has been broken. Furthermore, the ability of doing so would allow me to mould fuzzy or implicit structures in my code base into more concrete structures. What I mean is that when I'm coding, I often have a mental concept of my "working set" which might be something like "The GUI classes and the parts of the back-end which are called directly from the GUI". I need a tool that allows me to create views which match my mental model of the program slice which I'm working on. And these views should preferably be dynamic, so that if my code changes the views still correspond to the intended slice.
Excerpt from a discussion with a software developer:
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Conclusions
Declarative Source Code QueriesSpecify what to find in source code rather than focusing on how
Extract patterns, metrics, etc...
Hybrid SOUL LanguageMix of imperative and declarative paradigms
Direct manipulation of objects (easy of integration with external tools)
Domain-specific (i.e. language specific) unification of programs
35
Monday 30 March 2009
Active Software Documentation using Logic Metaprogramming
Links...
SOUL: http://prog.vub.ac.be/SOUL/
Declarative Metaprogramming: http://prog.vub.ac.be/DMP/
Intensional Software Views: http://www.intensional.be
36
Monday 30 March 2009