Active Software Documentation using Soul and IntensiVE

87
Département d’Ingénierie Informatique - Université catholique de Louvain Active Software Documentation using Soul and IntensiVE Johan Brichau, Kim Mens, Coen De Roover, Andy Kellens, Roel Wuyts Monday 30 March 2009

description

 

Transcript of Active Software Documentation using Soul and IntensiVE

Page 1: Active Software Documentation using Soul and IntensiVE

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

Page 2: Active Software Documentation using Soul and IntensiVE

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

Page 3: Active Software Documentation using Soul and IntensiVE

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

Page 4: Active Software Documentation using Soul and IntensiVE

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

Page 5: Active Software Documentation using Soul and IntensiVE

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

Page 6: Active Software Documentation using Soul and IntensiVE

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

Page 7: Active Software Documentation using Soul and IntensiVE

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

Page 8: Active Software Documentation using Soul and IntensiVE

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

Page 9: Active Software Documentation using Soul and IntensiVE

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

Page 10: Active Software Documentation using Soul and IntensiVE

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

Page 11: Active Software Documentation using Soul and IntensiVE

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

Page 12: Active Software Documentation using Soul and IntensiVE

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

Page 13: Active Software Documentation using Soul and IntensiVE

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

Page 14: Active Software Documentation using Soul and IntensiVE

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

Page 15: Active Software Documentation using Soul and IntensiVE

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

Page 16: Active Software Documentation using Soul and IntensiVE

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

Page 17: Active Software Documentation using Soul and IntensiVE

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

Page 18: Active Software Documentation using Soul and IntensiVE

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

Page 19: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Querying Code

8

- (Simple) name-based searches- Mostly textual matching

Monday 30 March 2009

Page 20: Active Software Documentation using Soul and IntensiVE

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

Page 21: Active Software Documentation using Soul and IntensiVE

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

Page 22: Active Software Documentation using Soul and IntensiVE

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

Page 23: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Meta Programming

10

SQL query

Expenses Database

Queries

“Standard” Program

Monday 30 March 2009

Page 24: Active Software Documentation using Soul and IntensiVE

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

Page 25: Active Software Documentation using Soul and IntensiVE

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

Page 26: Active Software Documentation using Soul and IntensiVE

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

Page 27: Active Software Documentation using Soul and IntensiVE

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

Page 28: Active Software Documentation using Soul and IntensiVE

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

Page 29: Active Software Documentation using Soul and IntensiVE

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

Page 30: Active Software Documentation using Soul and IntensiVE

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

Page 31: Active Software Documentation using Soul and IntensiVE

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

Page 32: Active Software Documentation using Soul and IntensiVE

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

Page 33: Active Software Documentation using Soul and IntensiVE

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

Page 34: Active Software Documentation using Soul and IntensiVE

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

Page 35: Active Software Documentation using Soul and IntensiVE

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

Page 36: Active Software Documentation using Soul and IntensiVE

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

Page 37: Active Software Documentation using Soul and IntensiVE

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

Page 38: Active Software Documentation using Soul and IntensiVE

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

Page 39: Active Software Documentation using Soul and IntensiVE

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

Page 40: Active Software Documentation using Soul and IntensiVE

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

Page 41: Active Software Documentation using Soul and IntensiVE

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

Page 42: Active Software Documentation using Soul and IntensiVE

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

Page 43: Active Software Documentation using Soul and IntensiVE

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

Page 44: Active Software Documentation using Soul and IntensiVE

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

Page 45: Active Software Documentation using Soul and IntensiVE

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

Page 46: Active Software Documentation using Soul and IntensiVE

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

Page 47: Active Software Documentation using Soul and IntensiVE

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

Page 48: Active Software Documentation using Soul and IntensiVE

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

Page 49: Active Software Documentation using Soul and IntensiVE

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

Page 50: Active Software Documentation using Soul and IntensiVE

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

Page 51: Active Software Documentation using Soul and IntensiVE

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

Page 52: Active Software Documentation using Soul and IntensiVE

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

Page 53: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Finding subclass dependencies

19

someMethod

SuperClass

SubClass

<<references>>

Monday 30 March 2009

Page 54: Active Software Documentation using Soul and IntensiVE

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

Page 55: Active Software Documentation using Soul and IntensiVE

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

Page 56: Active Software Documentation using Soul and IntensiVE

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

Page 57: Active Software Documentation using Soul and IntensiVE

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

Page 58: Active Software Documentation using Soul and IntensiVE

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

Page 59: Active Software Documentation using Soul and IntensiVE

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

Page 60: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Finding the Composite Pattern

22

Finding the “Composite” structure

Monday 30 March 2009

Page 61: Active Software Documentation using Soul and IntensiVE

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

Page 62: Active Software Documentation using Soul and IntensiVE

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

Page 63: Active Software Documentation using Soul and IntensiVE

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

Page 64: Active Software Documentation using Soul and IntensiVE

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

Page 65: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Teaser: Visual Query Language

25

Monday 30 March 2009

Page 66: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

SOUL: Hybrid Language

26

if classInHierarchyOf(?class,[ApplicationModel])

Monday 30 March 2009

Page 67: Active Software Documentation using Soul and IntensiVE

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

Page 68: Active Software Documentation using Soul and IntensiVE

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

Page 69: Active Software Documentation using Soul and IntensiVE

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

Page 70: Active Software Documentation using Soul and IntensiVE

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

Page 71: Active Software Documentation using Soul and IntensiVE

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

Page 72: Active Software Documentation using Soul and IntensiVE

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

Page 73: Active Software Documentation using Soul and IntensiVE

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

Page 74: Active Software Documentation using Soul and IntensiVE

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

Page 75: Active Software Documentation using Soul and IntensiVE

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

Page 76: Active Software Documentation using Soul and IntensiVE

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

Page 77: Active Software Documentation using Soul and IntensiVE

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

Page 78: Active Software Documentation using Soul and IntensiVE

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

Page 79: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

SOUL: Open Unification

31

Unification protocol implemented by parsetree items:

Monday 30 March 2009

Page 80: Active Software Documentation using Soul and IntensiVE

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

Page 81: Active Software Documentation using Soul and IntensiVE

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

Page 82: Active Software Documentation using Soul and IntensiVE

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

Page 83: Active Software Documentation using Soul and IntensiVE

Active Software Documentation using Logic Metaprogramming

Demonstration

32

Monday 30 March 2009

Page 84: Active Software Documentation using Soul and IntensiVE

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

Page 85: Active Software Documentation using Soul and IntensiVE

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

Page 86: Active Software Documentation using Soul and IntensiVE

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

Page 87: Active Software Documentation using Soul and IntensiVE

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