diff --git a/stockquote-week5/pom.xml b/stockquote-week5/pom.xml new file mode 100644 index 0000000..ec2af0f --- /dev/null +++ b/stockquote-week5/pom.xml @@ -0,0 +1,73 @@ + + 4.0.0 + com.origamisoftware.teach.effective + week-5-stock-ticker + jar + 1.0-SNAPSHOT + starter-app + http://maven.apache.org + + + UTF-8 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + -Xlint + ${project.build.sourceEncoding} + 1.8 + 1.8 + + + + + + + + + + junit + junit + 4.10 + jar + + + + mysql + mysql-connector-java + 5.1.6 + + + + javax.validation + validation-api + 1.0.0.GA + + + + org.mockito + mockito-all + 1.9.5 + + + + org.apache.httpcomponents + httpcore + 4.4 + + + + org.apache.ibatis + ibatis-sqlmap + 2.3.4.726 + + + diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.java new file mode 100644 index 0000000..571f075 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.java @@ -0,0 +1,144 @@ +package com.origamisoftware.teach.advanced.apps.stockquote; + +import com.origamisoftware.teach.advanced.model.StockQuery; +import com.origamisoftware.teach.advanced.model.StockQuote; +import com.origamisoftware.teach.advanced.services.StockService; +import com.origamisoftware.teach.advanced.services.StockServiceException; +import com.origamisoftware.teach.advanced.services.StockServiceFactory; + +import java.text.ParseException; +import java.util.List; + +/** + * A simple application that shows the StockService in action. + */ +public class BasicStockQuoteApplication { + + private StockService stockService; + + // an example of how to use enum - not part of assignment 3 but useful for assignment 4 + + /** + * An enumeration that indicates how the program terminates (ends) + */ + private enum ProgramTerminationStatusEnum { + + // for now, we just have normal or abnormal but could more specific ones as needed. + NORMAL(0), + ABNORMAL(-1); + + // when the program exits, this value will be reported to underlying OS + private int statusCode; + + /** + * Create a new ProgramTerminationStatusEnum + * + * @param statusCodeValue the value to return the OS. A value of 0 + * indicates success or normal termination. + * non 0 numbers indicate abnormal termination. + */ + private ProgramTerminationStatusEnum(int statusCodeValue) { + this.statusCode = statusCodeValue; + } + + /** + * @return The value sent to OS when the program ends. + */ + private int getStatusCode() { + return statusCode; + } + } + + /** + * Create a new Application. + * + * @param stockService the StockService this application instance should use for + * stock queries. + *

+ * NOTE: this is a example of Dependency Injection in action. + */ + public BasicStockQuoteApplication(StockService stockService) { + this.stockService = stockService; + } + + /** + * Given a stockQuery get back a the info about the stock to display to th user. + * + * @param stockQuery the stock to get data for. + * @return a String with the stock data in it. + * @throws StockServiceException If data about the stock can't be retrieved. This is a + * fatal error. + */ + public String displayStockQuotes(StockQuery stockQuery) throws StockServiceException { + StringBuilder stringBuilder = new StringBuilder(); + + List stockQuotes = + stockService.getQuote(stockQuery.getSymbol(), stockQuery.getFrom(), stockQuery.getUntil()); + + stringBuilder.append("Stock quotes for: " + stockQuery.getSymbol() + "\n"); + for (StockQuote stockQuote : stockQuotes) { + stringBuilder.append(stockQuote.toString()); + } + + return stringBuilder.toString(); + } + + /** + * Terminate the application. + * + * @param statusCode an enum value that indicates if the program terminated ok or not. + * @param diagnosticMessage A message to display to the user when the program ends. + * This should be an error message in the case of abnormal termination + *

+ * NOTE: This is an example of DRY in action. + * A program should only have one exit point. This makes it easy to do any clean up + * operations before a program quits from just one place in the code. + * It also makes for a consistent user experience. + */ + private static void exit(ProgramTerminationStatusEnum statusCode, String diagnosticMessage) { + if (statusCode == ProgramTerminationStatusEnum.NORMAL) { + System.out.println(diagnosticMessage); + } else if (statusCode == ProgramTerminationStatusEnum.ABNORMAL) { + System.err.println(diagnosticMessage); + } else { + throw new IllegalStateException("Unknown ProgramTerminationStatusEnum."); + } + System.exit(statusCode.getStatusCode()); + } + + /** + * Run the StockTicker application. + *

+ * When invoking the program supply one ore more stock symbols. + * + * @param args one or more stock symbols + */ + public static void main(String[] args) { + + // be optimistic init to positive values + ProgramTerminationStatusEnum exitStatus = ProgramTerminationStatusEnum.NORMAL; + String programTerminationMessage = "Normal program termination."; + if (args.length != 3) { + exit(ProgramTerminationStatusEnum.ABNORMAL, + "Please supply 3 arguments a stock symbol, a start date (MM/DD/YYYY) and end date (MM/DD/YYYY)"); + } + try { + + StockQuery stockQuery = new StockQuery(args[0], args[1], args[2]); + StockService stockService = StockServiceFactory.getInstance(); + BasicStockQuoteApplication basicStockQuoteApplication = + new BasicStockQuoteApplication(stockService); + basicStockQuoteApplication.displayStockQuotes(stockQuery); + + } catch (ParseException e) { + exitStatus = ProgramTerminationStatusEnum.ABNORMAL; + programTerminationMessage = "Invalid date data: " + e.getMessage(); + } catch (StockServiceException e) { + exitStatus = ProgramTerminationStatusEnum.ABNORMAL; + programTerminationMessage = "StockService failed: " + e.getMessage(); + } + + exit(exitStatus, programTerminationMessage); + System.out.println("Oops could not parse a date"); + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockData.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockData.java new file mode 100644 index 0000000..2ee6c88 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockData.java @@ -0,0 +1,25 @@ +package com.origamisoftware.teach.advanced.model; + +import java.text.SimpleDateFormat; + +/** + * Abstract Base class for classes that hold Stock data. + * Provides common code for such classes including date formatting. + */ +public abstract class StockData { + + /** + * Provide a single SimpleDateFormat for consistency + * and to avoid duplicated code. + */ + protected SimpleDateFormat simpleDateFormat; + + /** + * Base constructor for StockData classes. + * Initialize member data that is shared with sub classes. + */ + public StockData() { + simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd"); + } + +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuery.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuery.java new file mode 100644 index 0000000..37ddaba --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuery.java @@ -0,0 +1,60 @@ +package com.origamisoftware.teach.advanced.model; + + +import org.apache.http.annotation.Immutable; + +import javax.validation.constraints.NotNull; +import java.text.ParseException; +import java.util.Calendar; + +/** + * This class is used to a single query to stock service. + */ +@Immutable +public class StockQuery extends StockData{ + + private String symbol; + private Calendar from; + private Calendar until; + + /** + * Create a new instance from string data. This constructor will convert + * dates described as a String to Date objects. + * + * @param symbol the stock symbol + * @param from the start date as a string in the form of yyyy/MM/dd + * @param from the end date as a string in the form of yyyy/MM/dd + * @throws ParseException if the format of the date String is incorrect. If this happens + * the only recourse is to try again with a correctly formatted String. + */ + public StockQuery(@NotNull String symbol, @NotNull String from, @NotNull String until) throws ParseException { + super(); + this.symbol = symbol; + this.from = Calendar.getInstance(); + this.until = Calendar.getInstance(); + System.out.println(simpleDateFormat); + this.from.setTime(simpleDateFormat.parse(from)); + this.until.setTime(simpleDateFormat.parse(until)); + } + + /** + * @return get the stock symbol associated with this query + */ + public String getSymbol() { + return symbol; + } + + /** + * @return get the start Calendar associated with this query + */ + public Calendar getFrom() { + return from; + } + + /** + * @return get the end Calendar associated with this query + */ + public Calendar getUntil() { + return until; + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuote.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuote.java new file mode 100644 index 0000000..e19c713 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/model/StockQuote.java @@ -0,0 +1,61 @@ +package com.origamisoftware.teach.advanced.model; + +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Date; + +/** + * A container class that contains stock data. + */ +public class StockQuote extends StockData { + + private BigDecimal price; + private Date date; + private String symbol; + private Calendar from; + private Calendar until; + + /** + * Create a new instance of a StockQuote. + * + * @param price the share price for the given date + * @param date the date of the share price + * @param symbol the stock symbol. + */ + public StockQuote(BigDecimal price, Date date, String symbol) { + super(); + this.price = price; + this.date = date; + this.symbol = symbol; + } + /** + * @return Get the share price for the given date. + */ + public BigDecimal getPrice() { + return price; + } + + /** + * @return The date of the share price + */ + public Date getDate() { + return date; + } + + /** + * @return The stock symbol. + */ + public String getSymbol() { + return symbol; + } + + @Override + public String toString() { + String dateString = simpleDateFormat.format(date); + return "StockQuote{" + + "price=" + price + + ", date=" + dateString + + ", symbol='" + symbol + '\'' + + '}'; + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/DatabaseStockService.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/DatabaseStockService.java new file mode 100644 index 0000000..5f44614 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/DatabaseStockService.java @@ -0,0 +1,97 @@ +package com.origamisoftware.teach.advanced.services; + +import com.origamisoftware.teach.advanced.model.StockQuote; +import com.origamisoftware.teach.advanced.util.DatabaseConnectionException; +import com.origamisoftware.teach.advanced.util.DatabaseUtils; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +/** + * An implementation of the StockService interface that gets + * stock data from a database. + */ +public class DatabaseStockService implements StockService { + + /** + * Return the current price for a share of stock for the given symbol + * + * @param symbol the stock symbol of the company you want a quote for. + * e.g. APPL for APPLE + * @return a BigDecimal instance + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + @Override + public StockQuote getQuote(String symbol) throws StockServiceException { + // todo - this is a pretty lame implementation why? + List stockQuotes = null; + try { + Connection connection = DatabaseUtils.getConnection(); + Statement statement = connection.createStatement(); + String queryString = "select * from quotes where symbol = '" + symbol + "'"; + + ResultSet resultSet = statement.executeQuery(queryString); + stockQuotes = new ArrayList<>(resultSet.getFetchSize()); + while (resultSet.next()) { + String symbolValue = resultSet.getString("symbol"); + Date time = resultSet.getDate("time"); + BigDecimal price = resultSet.getBigDecimal("price"); + stockQuotes.add(new StockQuote(price, time, symbolValue)); + } + + } catch (DatabaseConnectionException | SQLException exception) { + throw new StockServiceException(exception.getMessage(), exception); + } + if (stockQuotes.isEmpty()) { + throw new StockServiceException("There is no stock data for:" + symbol); + } + return stockQuotes.get(0); + } + + /** + * Get a historical list of stock quotes for the provide symbol + * + * @param symbol the stock symbol to search for + * @param from the date of the first stock quote + * @param until the date of the last stock quote + * @return a list of StockQuote instances + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + @Override + public List getQuote(String symbol, Calendar from, Calendar until) throws StockServiceException { + + List stockQuotes = null; + try { + Connection connection = DatabaseUtils.getConnection(); + Statement statement = connection.createStatement(); + String queryString = "select * from quotes where symbol = '" + symbol + "' and DATE between '" + from + "' '" + until + "'"; + + ResultSet resultSet = statement.executeQuery(queryString); + stockQuotes = new ArrayList<>(resultSet.getFetchSize()); + while (resultSet.next()) { + String symbolValue = resultSet.getString("symbol"); + Date time = resultSet.getDate("time"); + BigDecimal price = resultSet.getBigDecimal("price"); + stockQuotes.add(new StockQuote(price, time, symbolValue)); + } + + } catch (DatabaseConnectionException | SQLException exception) { + throw new StockServiceException(exception.getMessage(), exception); + } + if (stockQuotes.isEmpty()) { + throw new StockServiceException("There is no stock data for:" + symbol); + } + return stockQuotes; + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/SimpleStockService.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/SimpleStockService.java new file mode 100644 index 0000000..1cc89c6 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/SimpleStockService.java @@ -0,0 +1,55 @@ +package com.origamisoftware.teach.advanced.services; + +import com.origamisoftware.teach.advanced.model.StockQuote; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * An implementation of the StockService that returns hard coded data. + */ +public class SimpleStockService implements StockService { + + /** + * Return the current price for a share of stock for the given symbol + * + * @param symbol the stock symbol of the company you want a quote for. + * e.g. APPL for APPLE + * @return a BigDecimal instance + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + @Override + public StockQuote getQuote(String symbol) { + // a dead simple implementation. + return new StockQuote(new BigDecimal(100), Calendar.getInstance().getTime(), symbol); + } + + /** + * Get a historical list of stock quotes for the provide symbol + * + * @param symbol the stock symbol to search for + * @param from the date of the first stock quote + * @param until the date of the last stock quote + * @return a list of StockQuote instances + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + @Override + public List getQuote(String symbol, Calendar from, Calendar until) { + // a dead simple implementation. + List stockQuotes = new ArrayList<>(); + Date aDay = from.getTime(); + while (until.after(aDay)) { + stockQuotes.add(new StockQuote(new BigDecimal(100), aDay, symbol)); + from.add(Calendar.DAY_OF_YEAR, 1); + aDay = from.getTime(); + } + return stockQuotes; + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockService.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockService.java new file mode 100644 index 0000000..d702731 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockService.java @@ -0,0 +1,40 @@ +package com.origamisoftware.teach.advanced.services; + +import com.origamisoftware.teach.advanced.model.StockQuote; + +import java.util.Calendar; +import java.util.List; + +/** + * This API describes how to get stock data from an external resource. + */ +public interface StockService { + + + /** + * Return the current price for a share of stock for the given symbol + * + * @param symbol the stock symbol of the company you want a quote for. + * e.g. APPL for APPLE + * @return a BigDecimal instance + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + StockQuote getQuote(String symbol) throws StockServiceException; + + /** + * Get a historical list of stock quotes for the provide symbol + * + * @param symbol the stock symbol to search for + * @param from the date of the first stock quote + * @param until the date of the last stock quote + * @return a list of StockQuote instances + * @throws StockServiceException if using the service generates an exception. + * If this happens, trying the service may work, depending on the actual cause of the + * error. + */ + List getQuote(String symbol, Calendar from, Calendar until) throws StockServiceException; + +} + diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceException.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceException.java new file mode 100644 index 0000000..efcfa21 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceException.java @@ -0,0 +1,37 @@ +package com.origamisoftware.teach.advanced.services; + +/** + * Used to signal a problem with the StockService. + */ +public class StockServiceException extends Exception { + + /** + * Constructs a new exception with the specified detail message. The + * cause is not initialized, and may subsequently be initialized by + * a call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + */ + public StockServiceException(String message) { + super(message); + } + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public StockServiceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceFactory.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceFactory.java new file mode 100644 index 0000000..1bc4e47 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/services/StockServiceFactory.java @@ -0,0 +1,45 @@ +package com.origamisoftware.teach.advanced.services; + +import com.origamisoftware.teach.advanced.model.StockQuote; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * A factory that returns a StockService instance. + */ +public class StockServiceFactory { + + /** + * Prevent instantiations + */ + private StockServiceFactory() {} + + /** + * + * @return get a StockService instance + */ + public static DatabaseStockService getInstance() { + return new DatabaseStockService() { + @Override + public StockQuote getQuote(String symbol) throws StockServiceException { + return new StockQuote(new BigDecimal(100), Calendar.getInstance().getTime(), symbol); + } + + @Override + public List getQuote(String symbol, Calendar from, Calendar until) throws StockServiceException { + List stockQuotes = new ArrayList<>(); + Date aDay = from.getTime(); + while (until.after(aDay)) { + stockQuotes.add(new StockQuote(new BigDecimal(100),aDay,symbol)); + from.add(Calendar.DAY_OF_YEAR, 1); + aDay = from.getTime(); + } + return stockQuotes; } + }; + } + +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java new file mode 100644 index 0000000..ea8d91e --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java @@ -0,0 +1,25 @@ +package com.origamisoftware.teach.advanced.util; + +/** + * This class is used to signal a problem connecting to a database. + */ +public class DatabaseConnectionException extends Exception { + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DatabaseConnectionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java new file mode 100644 index 0000000..bc09f7d --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java @@ -0,0 +1,25 @@ +package com.origamisoftware.teach.advanced.util; + +/** + * This class is used to signal a problem initializing to a database. + */ +public class DatabaseInitializationException extends Exception { + + /** + * Constructs a new exception with the specified detail message and + * cause.

Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 1.4 + */ + public DatabaseInitializationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java new file mode 100644 index 0000000..708b52a --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java @@ -0,0 +1,65 @@ +package com.origamisoftware.teach.advanced.util; + +import com.ibatis.common.jdbc.ScriptRunner; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * A class that contains database related utility methods. + */ +public class DatabaseUtils { + + // in a real program these values would be a configurable property and not hard coded. + // JDBC driver name and database URL + private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; + private static final String DB_URL = "jdbc:mysql://localhost:3306/stocks"; + + // Database credentials + private static final String USER = "monty"; + private static final String PASS = "some_pass"; + + public static Connection getConnection() throws DatabaseConnectionException{ + Connection connection = null; + try { + Class.forName("com.mysql.jdbc.Driver"); + connection = DriverManager.getConnection(DB_URL, USER, PASS); + } catch (ClassNotFoundException | SQLException e) { + throw new DatabaseConnectionException("Could not connection to database." + e.getMessage(), e); + } + return connection; + } + + /** + * A utility method that runs a db initialize script. + * @param initializationScript full path to the script to run to create the schema + * @throws DatabaseInitializationException + */ + public static void initializeDatabase(String initializationScript) throws DatabaseInitializationException { + + Connection connection = null; + try { + connection = getConnection(); + ScriptRunner runner = new ScriptRunner(connection, false, false); + InputStream inputStream = new FileInputStream(initializationScript); + + InputStreamReader reader = new InputStreamReader(inputStream); + + runner.runScript(reader); + reader.close(); + connection.commit(); + connection.close(); + + } catch (DatabaseConnectionException | SQLException |IOException e) { + throw new DatabaseInitializationException("Could not initialize db because of:" + + e.getMessage(),e); + } + + + } +} diff --git a/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/ProgramConfiguration.java b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/ProgramConfiguration.java new file mode 100644 index 0000000..0b03a55 --- /dev/null +++ b/stockquote-week5/src/main/java/com/origamisoftware/teach/advanced/util/ProgramConfiguration.java @@ -0,0 +1,15 @@ +package com.origamisoftware.teach.advanced.util; + +import java.util.Properties; + +/** + * A Utility class that provides application properties and + * configuration settings. + */ +public class ProgramConfiguration { + + public static Properties getApplicationProperties() { + return null; + } + +} diff --git a/stockquote-week5/src/main/sql/stocks_db_initialization.sql b/stockquote-week5/src/main/sql/stocks_db_initialization.sql new file mode 100644 index 0000000..3437e25 --- /dev/null +++ b/stockquote-week5/src/main/sql/stocks_db_initialization.sql @@ -0,0 +1,15 @@ +/** create the stocks database */ + +DROP TABLE IF EXISTS quotes CASCADE; +CREATE TABLE quotes( + id INT NOT NULL AUTO_INCREMENT, + symbol VARCHAR(4) NOT NULL, + time DATETIME NOT NULL, + price DECIMAL NOT NULL, + PRIMARY KEY ( id ) +); + +INSERT INTO quotes (symbol,time,price) VALUES ('GOOG','2004-08-19 00:00:01','85.00'); +INSERT INTO quotes (symbol,time,price) VALUES ('GOOG','2015-02-03 00:00:01','527.35'); +INSERT INTO quotes (symbol,time,price) VALUES ('APPL','2000-01-01 00:00:01','118.27'); +INSERT INTO quotes (symbol,time,price) VALUES ('AMZN','2015-02-03 00:00:01','363.21'); diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.java new file mode 100644 index 0000000..fa3e3f2 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.java @@ -0,0 +1,68 @@ +package com.origamisoftware.teach.advanced.apps.stockquote; + +import com.origamisoftware.teach.advanced.model.StockQuery; +import com.origamisoftware.teach.advanced.model.StockQuote; +import com.origamisoftware.teach.advanced.services.StockService; +import com.origamisoftware.teach.advanced.services.StockServiceException; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests for BasicStockQuoteApplication + */ +public class BasicStockQuoteApplicationTest { + + private BasicStockQuoteApplication basicStockQuoteApplication; + private StockService stockServiceMock; + + @Before + public void setUp() { + stockServiceMock = mock(StockService.class); + } + + @Test + public void testValidConstruction() { + basicStockQuoteApplication = new BasicStockQuoteApplication(stockServiceMock); + assertNotNull("Basic construction works"); + } + + @Test + public void testDisplayResults() throws ParseException, StockServiceException { + basicStockQuoteApplication = new BasicStockQuoteApplication(stockServiceMock); + String symbol = "APPL"; + String from = "2011/10/29"; + String until = "2011/11/29"; + StockQuery stockQuery = new StockQuery(symbol, from, until); + + List stockQuotes = new ArrayList<>(); + StockQuote stockQuoteFromDate = new StockQuote(new BigDecimal(100), stockQuery.getFrom().getTime(), stockQuery.getSymbol()); + stockQuotes.add(stockQuoteFromDate); + StockQuote stockQuoteUntilDate = new StockQuote(new BigDecimal(100), stockQuery.getUntil().getTime(), stockQuery.getSymbol()); + stockQuotes.add(stockQuoteUntilDate); + + when(stockServiceMock.getQuote(any(String.class), any(Calendar.class), any(Calendar.class))).thenReturn(stockQuotes); + + String output = basicStockQuoteApplication.displayStockQuotes(stockQuery); + assertTrue("make sure symbol appears in output", output.contains(symbol)); + assertTrue("make sure from date appears in output", output.contains(from)); + assertTrue("make sure until date in output", output.contains(until)); + + } + + @Test(expected = NullPointerException.class) + public void testMainNegative() { + BasicStockQuoteApplication.main(null); + } +} diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQueryTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQueryTest.java new file mode 100644 index 0000000..6574e84 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQueryTest.java @@ -0,0 +1,19 @@ +package com.origamisoftware.teach.advanced.model; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Unit test for StockQuery Class + */ +public class StockQueryTest { + + @Test + public void testBasicConstruction() throws Exception{ + String symbol = "APPL"; + StockQuery stockQuery = new StockQuery(symbol,"2010/11/11","2011/11/11"); + assertEquals("Verify construction", symbol, stockQuery.getSymbol()); + } + +} diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQuoteTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQuoteTest.java new file mode 100644 index 0000000..ad47fb1 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/model/StockQuoteTest.java @@ -0,0 +1,44 @@ +package com.origamisoftware.teach.advanced.model; + +import org.junit.Before; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Date; + +import static org.junit.Assert.assertEquals; + +/** + * JUnit test for StockQuote class + */ +public class StockQuoteTest { + + private BigDecimal price; + private Date date; + private String symbol; + private StockQuote stockQuote; + + @Before + public void setUp() { + price = new BigDecimal(100); + date = Calendar.getInstance().getTime(); + symbol = "APPL"; + stockQuote = new StockQuote(price, date, symbol); + } + + @Test + public void testGetPrice() { + assertEquals("Share price is correct", price, stockQuote.getPrice()); + } + + @Test + public void testGetDate() { + assertEquals("Share date is correct", date, stockQuote.getDate()); + } + + @Test + public void testGetSymbol() { + assertEquals("Symbol is correct", symbol, stockQuote.getSymbol()); + } +} diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.java new file mode 100644 index 0000000..ae2a556 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.java @@ -0,0 +1,22 @@ +package com.origamisoftware.teach.advanced.services; + +import com.origamisoftware.teach.advanced.model.StockQuote; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Unit tests for the DatabaseStockService + */ +public class DatabaseStockServiceTest { + + @Test + public void testGetQuote() throws Exception { + DatabaseStockService databaseStockService = new DatabaseStockService(); + String symbol = "APPL"; + StockQuote stockQuote = databaseStockService.getQuote(symbol); + assertNotNull("Verify we can get a stock quote from the db", stockQuote); + assertEquals("Make sure the symbols match", symbol, stockQuote.getSymbol()); + } +} diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.java new file mode 100644 index 0000000..fd605e9 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.java @@ -0,0 +1,17 @@ +package com.origamisoftware.teach.advanced.services; + +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +/** + * JUnit test for StockServiceFactory + */ +public class StockServiceFactoryTest { + + @Test + public void testGetInstance() { + StockService stockService = StockServiceFactory.getInstance(); + assertNotNull(stockService); + } +} diff --git a/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java new file mode 100644 index 0000000..f775571 --- /dev/null +++ b/stockquote-week5/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java @@ -0,0 +1,38 @@ +package com.origamisoftware.teach.advanced.util; + +import org.junit.Test; + +import java.sql.Connection; +import java.sql.Statement; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Tests for the DatabaseUtils class + */ +public class DatabaseUtilsTest { + + @Test + public void testGetConnection() throws Exception{ + Connection connection = DatabaseUtils.getConnection(); + assertNotNull("verify that we can get a connection ok",connection); + } + + @Test + public void testGetConnectionWorks() throws Exception{ + Connection connection = DatabaseUtils.getConnection(); + Statement statement = connection.createStatement(); + boolean execute = statement.execute("select * from quotes"); + assertTrue("verify that we can execute a statement",execute); + } + + @Test + public void testInitializeDatabaseWorks(String initializeDatabase) throws Exception{ + Connection connection = DatabaseUtils.getConnection(); + Statement statement = connection.createStatement(); + boolean execute = statement.execute("select * from quotes"); + assertNotNull("verify that the DB is NotNull",execute); + } + +} diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication$ProgramTerminationStatusEnum.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication$ProgramTerminationStatusEnum.class new file mode 100644 index 0000000..7a13f96 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication$ProgramTerminationStatusEnum.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.class new file mode 100644 index 0000000..161fe9d Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplication.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockData.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockData.class new file mode 100644 index 0000000..e2f53b3 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockData.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuery.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuery.class new file mode 100644 index 0000000..cc8167c Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuery.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuote.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuote.class new file mode 100644 index 0000000..b4359c2 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/model/StockQuote.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/DatabaseStockService.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/DatabaseStockService.class new file mode 100644 index 0000000..282471e Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/DatabaseStockService.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/SimpleStockService.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/SimpleStockService.class new file mode 100644 index 0000000..da1d221 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/SimpleStockService.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockService.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockService.class new file mode 100644 index 0000000..b387788 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockService.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceException.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceException.class new file mode 100644 index 0000000..0aa546a Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceException.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory$1.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory$1.class new file mode 100644 index 0000000..f2d7453 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory$1.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory.class new file mode 100644 index 0000000..37855d0 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/services/StockServiceFactory.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.class new file mode 100644 index 0000000..bb210c5 Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.class new file mode 100644 index 0000000..3f8091c Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseUtils.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseUtils.class new file mode 100644 index 0000000..a07930e Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/DatabaseUtils.class differ diff --git a/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/ProgramConfiguration.class b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/ProgramConfiguration.class new file mode 100644 index 0000000..7d57f7c Binary files /dev/null and b/stockquote-week5/target/classes/com/origamisoftware/teach/advanced/util/ProgramConfiguration.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.class new file mode 100644 index 0000000..3a2e06c Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/apps/stockquote/BasicStockQuoteApplicationTest.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQueryTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQueryTest.class new file mode 100644 index 0000000..d49fa98 Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQueryTest.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQuoteTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQuoteTest.class new file mode 100644 index 0000000..b453f12 Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/model/StockQuoteTest.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.class new file mode 100644 index 0000000..dea8599 Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/DatabaseStockServiceTest.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.class new file mode 100644 index 0000000..13d9476 Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/services/StockServiceFactoryTest.class differ diff --git a/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.class b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.class new file mode 100644 index 0000000..75ed0e2 Binary files /dev/null and b/stockquote-week5/target/test-classes/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.class differ diff --git a/stockquote-week5/week-5-stock-ticker.iml b/stockquote-week5/week-5-stock-ticker.iml new file mode 100644 index 0000000..bad55fd --- /dev/null +++ b/stockquote-week5/week-5-stock-ticker.iml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file