Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions BasicStockQuoteApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
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.ServiceFactory;
import com.origamisoftware.teach.advanced.util.Interval;
import com.origamisoftware.teach.advanced.xml.Stock;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
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.
* <p/>
* NOTE: this is a example of Dependency Injection in action.
*/
public BasicStockQuoteApplication(StockService stockService) {
this.stockService = stockService;
}

/**
* Given a <CODE>stockQuery</CODE> 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<StockQuote> stockQuotes =
stockService.getQuote(stockQuery.getSymbol(),
stockQuery.getFrom(),
stockQuery.getUntil(),
Interval.DAY); // get one quote for each day in the from until date range.

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
* <p/>
* 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.
* <p/>
*
* @param args one or more stock symbols
*/

private static String xmlInstance =
"<stocks>\n" +
" <stock symbol=\"VNET\" price=\"110.10\" time=\"2015-02-10 00:00:01\"/>\n" +
" <stock symbol=\"AGTK\" price=\"120.10\" time=\"2015-02-10 00:00:01\"/>\n" +
" <stock symbol=\"AKAM\" price=\"3.10\" time=\"2015-02-10 00:00:01\"/>\n" +
" <stock symbol=\"AOL\" price=\"30.10\" time=\"2015-02-10 00:00:01\"/>\n" +
"</stocks>";
public static void main(String[] args) throws JAXBException {

// 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 = ServiceFactory.getStockService();
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();
} catch (Throwable t) {
exitStatus = ProgramTerminationStatusEnum.ABNORMAL;
programTerminationMessage = "General application error: " + t.getMessage();
}

// here is how to go from XML to Java
JAXBContext jaxbContext = JAXBContext.newInstance(Stock.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Stock stock = (Stock) unmarshaller.unmarshal(new StringReader(xmlInstance));
System.out.println(stock.toString());

// here is how to go from Java to XML
JAXBContext context = JAXBContext.newInstance(Stock.class);
Marshaller marshaller = context.createMarshaller();
//for pretty-print XML in JAXB
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(stock, System.out);

exit(exitStatus, programTerminationMessage);
System.out.println("Oops could not parse a date");
}
}
20 changes: 20 additions & 0 deletions InvalidXMLException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.origamisoftware.teach.advanced.util;

/**
* Used to signal invalid XML or other JAXB related issues.
*/
public class InvalidXMLException extends Exception{

/**
* Constructs a new exception with the specified detail message,
* cause, suppression enabled or disabled, and writable stack
* trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
*/
protected InvalidXMLException(String message, Throwable cause) {
super(message, cause);
}
}
106 changes: 106 additions & 0 deletions XMLUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.origamisoftware.teach.advanced.util;

import com.origamisoftware.teach.advanced.xml.XMLDomainObject;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.StringReader;

/**
* A collection of helper methods for marshaling and unmarshaling XML instances.
*/
public class XMLUtils {

/**
* Put the provided XML String into the specified XML Domain Object using JAXB without using
* schema validation.
*
* @param xmlInstance an XML instance that matched the XML Domain object specified by T
* @param T a XML Domain object class which corresponds the XML instance
* @return XML Domain Object of type T populated with values in the provided String.
* @throws InvalidXMLException if the provided xmlInstance cannot be successfully parsed.

*/
public static <T extends XMLDomainObject> T unmarshall(String xmlInstance, Class T)
throws InvalidXMLException {
T returnValue;
try {
Unmarshaller unmarshaller = createUnmarshaller(T);
returnValue = (T) unmarshaller.unmarshal(new StringReader(xmlInstance));
} catch (JAXBException e) {
throw new InvalidXMLException("JAXBException issue: " +e.getMessage(),e);
}
return returnValue;
}

/**
* Put the provided XML String into the specified XML Domain Object using JAXB using
* schema validation.
*
* @param xmlInstance an XML instance that matched the XML Domain object specified by T
* @param T a XML Domain object class which corresponds the XML instance
* @param schemaName the name of the .xsd schema which must be on the classpath - used for validation.
* @return XML Domain Object of type T populated with values in the provided String.
* @throws InvalidXMLException if the provided xmlInstance cannot be successfully parsed.
*/
public static <T extends XMLDomainObject> T unmarshall(String xmlInstance, Class T, String schemaName)
throws InvalidXMLException {

T returnValue;
try {
InputStream resourceAsStream = XMLUtils.class.getResourceAsStream(schemaName);
Source schemaSource = new StreamSource(resourceAsStream);
if (resourceAsStream == null) {
throw new IllegalStateException("Schema: " + schemaName + " on classpath. " +
"Could not validate input XML");
}
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaSource);
Unmarshaller unmarshaller = createUnmarshaller(T);
unmarshaller.setSchema(schema);

returnValue = (T) unmarshaller.unmarshal(new StringReader(xmlInstance));
} catch (JAXBException | SAXException e) {
throw new InvalidXMLException(e.getMessage(),e);
}
return returnValue;
}

/**
* Serializes the domainClass into an XML instance which is returned as a String.
* @param domainClass the XML model class.
* @return a String which is a valid XML instance for the domain class provided.
* @throws InvalidXMLException is the object can't be parsed into XML.
*/
public static String marshall(XMLDomainObject domainClass) throws InvalidXMLException {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
JAXBContext context = JAXBContext.newInstance(domainClass.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(domainClass, byteArrayOutputStream);
return byteArrayOutputStream.toString();
} catch (JAXBException e) {
throw new InvalidXMLException(e.getMessage(),e);
}

}



private static Unmarshaller createUnmarshaller(Class T) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(T);
return jaxbContext.createUnmarshaller();
}

}
Loading