diff --git a/BasicStockQuoteApplication.java b/BasicStockQuoteApplication.java
new file mode 100644
index 0000000..84409c7
--- /dev/null
+++ b/BasicStockQuoteApplication.java
@@ -0,0 +1,143 @@
+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/BasicStockQuoteApplicationTest.java b/BasicStockQuoteApplicationTest.java
new file mode 100644
index 0000000..fa3e3f2
--- /dev/null
+++ b/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/SimpleStockService.java b/SimpleStockService.java
new file mode 100644
index 0000000..1cc89c6
--- /dev/null
+++ b/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.java b/StockQuote.java
new file mode 100644
index 0000000..d856e67
--- /dev/null
+++ b/StockQuote.java
@@ -0,0 +1,58 @@
+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;
+ /**
+ * 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/StockQuoteTest.java b/StockQuoteTest.java
new file mode 100644
index 0000000..ad47fb1
--- /dev/null
+++ b/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/StockService.java b/StockService.java
new file mode 100644
index 0000000..d702731
--- /dev/null
+++ b/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/StockServiceFactory.java b/StockServiceFactory.java
new file mode 100644
index 0000000..1bc4e47
--- /dev/null
+++ b/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/StockServiceFactoryTest.java b/StockServiceFactoryTest.java
new file mode 100644
index 0000000..fd605e9
--- /dev/null
+++ b/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);
+ }
+}