aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/edu/brown/cs/student/term/parsing/LocalXmlParser.java38
-rw-r--r--src/main/java/edu/brown/cs/student/term/parsing/Transaction.java171
-rw-r--r--src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java37
-rw-r--r--src/main/java/edu/brown/cs/student/term/parsing/XmlParser.java37
-rw-r--r--src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java76
-rw-r--r--src/main/java/edu/brown/cs/student/term/trade/Trade.java4
-rw-r--r--src/test/java/edu/brown/cs/student/TransactionTest.java96
-rw-r--r--src/test/java/edu/brown/cs/student/XmlParserTest.java168
8 files changed, 627 insertions, 0 deletions
diff --git a/src/main/java/edu/brown/cs/student/term/parsing/LocalXmlParser.java b/src/main/java/edu/brown/cs/student/term/parsing/LocalXmlParser.java
new file mode 100644
index 0000000..27c3988
--- /dev/null
+++ b/src/main/java/edu/brown/cs/student/term/parsing/LocalXmlParser.java
@@ -0,0 +1,38 @@
+package edu.brown.cs.student.term.parsing;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.io.File;
+import java.io.IOException;
+
+public class LocalXmlParser extends XmlParser {
+ public LocalXmlParser() {
+ super();
+ }
+
+ /**
+ * Method used to parse the xml file.
+ *
+ * @param pathToXml The path to the xml text file.
+ * @return The tree structure parsed as an xml doc.
+ */
+ @Override
+ public Document parse(String pathToXml) {
+ // TODO: change to online hosted file option
+ // Creating the file reference.
+ System.err.println("LOG: To make file reference for " + pathToXml + " in " + getClass());
+ File file = new File(pathToXml);
+
+ // Parsing the file.
+ try {
+ System.err.println("LOG: Calling builder.parse() in " + getClass());
+ return builder.parse(file);
+ } catch (SAXException e) {
+ System.err.println("INTERNAL: SAX " + getClass() + " : " + e.getClass());
+ } catch (IOException e) {
+ System.err.println("INTERNAL: IO " + getClass() + " : " + e.getClass());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java
new file mode 100644
index 0000000..2111048
--- /dev/null
+++ b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java
@@ -0,0 +1,171 @@
+package edu.brown.cs.student.term.parsing;
+
+import edu.brown.cs.student.term.hub.Holder;
+import edu.brown.cs.student.term.trade.Trade;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * This class represents the transaction data from the xml file.
+ */
+public class Transaction {
+ private Document doc;
+ private final List<Trade> trades;
+ private final String personName;
+ private final int id;
+ private final String ticker;
+
+ /**
+ * Constructor that represents the transaction from the document.
+ * @param document The document parsed from the xml file.
+ */
+ public Transaction(Document document) {
+ // TODO: add log comments
+ doc = document;
+ trades = new ArrayList<>();
+
+ personName = personName();
+ id = id();
+ ticker = ticker();
+
+ // There are two types of transactions within the xml - derivative and non derivative.
+ NodeList nonDerivative = document.getElementsByTagName("nonDerivativeTransaction");
+ //NodeList derivative = document.getElementsByTagName("derivativeTransaction");
+ // Processing both of their trades into the trades instance var.
+ processTransactions(nonDerivative);
+ //processTransactions(derivative);
+ }
+
+ /**
+ * Takes a transaction as a node list, then processes and stores them into trades.
+ * @param tradesAsNodes The trades within the transaction as a nodelist.
+ */
+ private void processTransactions(NodeList tradesAsNodes) {
+ int numTrades = tradesAsNodes.getLength();
+ for(int i = 0; i < numTrades; i++) {
+ NodeList tradeValues = getValueList(tradesAsNodes.item(i));
+
+ // This stages the params for the trade.
+ // TODO: update with real timestamp
+ double ts = getDate(tradeValues).hashCode();
+ int isBuy = getIsBuy(tradeValues) ? 1 : 0;
+ int numShares = getNumShares(tradeValues);
+ // TODO: update id? unique for each holder?
+ Holder holder = new Holder(id, personName);
+
+ Trade trade = new Trade(id, ticker, ts, isBuy, numShares, holder);
+ trades.add(trade);
+ }
+
+ doc = null;
+ }
+
+ /**
+ * Extracts the id of the transaction from the document.
+ * @return The id.
+ */
+ private int id() {
+ // Id of transaction
+ NodeList idNode = doc.getElementsByTagName("rptOwnerCik");
+ // TODO: add error parsing
+ return Integer.parseInt(idNode.item(0).getTextContent());
+ }
+
+ /**
+ * Extracts the person's name of the transaction from the document.
+ * @return The person's name.
+ */
+ private String personName() {
+ // Name of person
+ NodeList nameNode = doc.getElementsByTagName("rptOwnerName");
+ return nameNode.item(0).getTextContent();
+ }
+
+ /**
+ * Extracts the security ticker of the transaction from the document
+ * @return The ticker.
+ */
+ private String ticker() {
+ // Ticker of security
+ NodeList idNode = doc.getElementsByTagName("issuerTradingSymbol");
+ return idNode.item(0).getTextContent();
+ }
+
+ /**
+ * Extracts the trade data of one trade within a transaction.
+ * @param trade One trade from the transaction as a node.
+ * @return A nodelist with each element holding specific info of the trade.
+ */
+ public NodeList getValueList(Node trade) {
+ // Data of trade in an array of values
+ assert trade.getNodeType() == Node.ELEMENT_NODE;
+ Element tradeElement = (Element) trade;
+ return tradeElement.getElementsByTagName("value");
+ }
+
+ /**
+ * Extracts the trade date from a trade node.
+ * @param values The value array representing the trade.
+ * @return The date in mm-dd-yyyy format as a string.
+ */
+ public String getDate(NodeList values) {
+ return values.item(1).getTextContent();
+ }
+
+ /**
+ * Extracts the number of shares moved from the trade.
+ * @param values The value array representing the trade.
+ * @return The number of shares.
+ */
+ public int getNumShares(NodeList values) {
+ return Integer.parseInt(values.item(2).getTextContent());
+ }
+
+ /**
+ * Extracts the price each share cost from the trade.
+ * @param values The value array representing the trade.
+ * @return The price of each share.
+ */
+ public int getPriceShares(NodeList values) {
+ return Integer.parseInt(values.item(3).getTextContent());
+ }
+
+ /**
+ * Determines whether the shares in the trade were bought or sold.
+ * @param values The value array representing the trade.
+ * @return True if they were bought (acquired). False, if sold.
+ */
+ public boolean getIsBuy(NodeList values) {
+ return values.item(4).getTextContent().equals("A");
+ }
+
+ /**
+ * Returns the list of trades that occurred within the transaction.
+ * @return A list of trade objects.
+ */
+ public List<Trade> getTrades() {
+ return trades;
+ }
+
+ /**
+ * Accessor method that returns the id of the transaction.
+ * @return The id.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Accessor method that returns the person's name who did the transaction.
+ * @return The name of whom did the transaction.
+ */
+ public String getPersonName() {
+ return personName;
+ }
+}
diff --git a/src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java b/src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java
new file mode 100644
index 0000000..440b898
--- /dev/null
+++ b/src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java
@@ -0,0 +1,37 @@
+package edu.brown.cs.student.term.parsing;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+public class UrlXmlParser extends XmlParser{
+ public UrlXmlParser() {
+ super();
+ }
+
+ /**
+ * Method used to parse the xml file.
+ *
+ * @param pathToXml The path to the xml text file.
+ * @return The tree structure parsed as an xml doc.
+ */
+ @Override
+ public Document parse(String pathToXml) {
+ try {
+ System.err.println("LOG: To make url class in parse() of " + getClass());
+ URL url = new URL(pathToXml);
+ System.err.println("LOG: To establish urlConnection in parse() of " + getClass());
+ URLConnection conn = url.openConnection();
+ System.err.println("LOG: Calling builder.parse() in " + getClass());
+ return builder.parse(conn.getInputStream());
+ } catch (SAXException e) {
+ System.err.println("INTERNAL: SAX " + getClass() + " : " + e.getClass());
+ } catch (IOException e) {
+ System.err.println("INTERNAL: IO " + getClass() + " : " + e.getClass());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/edu/brown/cs/student/term/parsing/XmlParser.java b/src/main/java/edu/brown/cs/student/term/parsing/XmlParser.java
new file mode 100644
index 0000000..d8182d6
--- /dev/null
+++ b/src/main/java/edu/brown/cs/student/term/parsing/XmlParser.java
@@ -0,0 +1,37 @@
+package edu.brown.cs.student.term.parsing;
+
+import org.w3c.dom.Document;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+public abstract class XmlParser {
+ protected DocumentBuilder builder = null;
+
+ /**
+ * This constructor crates and saves the builder that turns the xml text into a tree stricture.
+ */
+ protected XmlParser() {
+ // Builds the immutable factory
+ System.err.println("LOG: Constructor of " + getClass() + ". To make XML parser factory.");
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(true);
+ factory.setIgnoringElementContentWhitespace(true);
+
+ // Creates the builder from the factory
+ try {
+ System.err.println("LOG: To make documentBuilder in " + getClass());
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ System.err.println("INTERNAL: " + getClass() + " : " + e.getClass());
+ }
+ }
+
+ /**
+ * Method used to parse the xml file.
+ * @param pathToXml The path to the xml text file.
+ * @return The tree structure parsed as an xml doc.
+ */
+ public abstract Document parse(String pathToXml);
+}
diff --git a/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java b/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java
new file mode 100644
index 0000000..a20c23b
--- /dev/null
+++ b/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java
@@ -0,0 +1,76 @@
+package edu.brown.cs.student.term.repl.commands;
+
+import edu.brown.cs.student.term.DatabaseQuerier;
+import edu.brown.cs.student.term.parsing.Transaction;
+import edu.brown.cs.student.term.parsing.UrlXmlParser;
+import edu.brown.cs.student.term.repl.Command;
+import edu.brown.cs.student.term.trade.Trade;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+public class LoadCommand implements Command {
+ private final static Connection CONN = DatabaseQuerier.getConn();
+ private final static UrlXmlParser URL_XML_PARSER = new UrlXmlParser();
+
+ /**
+ * Main run method for every command.
+ *
+ * @param args arguments for the command
+ */
+ @Override
+ public String run(String[] args) {
+ // TODO: add log comments
+ System.err.println("LOG: Entered .run() of " + getClass());
+ // TODO: call to api for urls to call through the urlxmlparser from reagan
+ String[] urls = new String[1];
+ for (String url : urls) {
+ try {
+ System.err.println("LOG: Calling loadTransactionIntoDB() in " + getClass());
+ loadTransactionIntoDB(url);
+ } catch (SQLException throwables) {
+ System.err.println("INTERNAL: SQLException in .run() of " + getClass());
+ //throwables.printStackTrace();
+ }
+ }
+ return "Loaded?";
+ }
+
+ /**
+ * Loads a whole transaction, which can have multiple trades, into the DB.
+ * @param url The url to the public xml file.
+ * @throws SQLException If the prep statement fails or db doesn't exist, throws.
+ */
+ private static void loadTransactionIntoDB(String url) throws SQLException {
+ System.err.println("LOG: Parsing XML into transaction in loadTransactionIntoDB(). URL: " + url);
+ Transaction helper = new Transaction(URL_XML_PARSER.parse(url));
+ for(Trade trade : helper.getTrades()) {
+ System.err.println("LOG: Loading a trade into DB -> " + trade);
+ loadTradeIntoDB(trade);
+ System.err.println("LOG: Loaded that trade.");
+ }
+ }
+
+ /**
+ * Loads one trade into the DB.
+ * @param trade The trade to be loaded.
+ * @throws SQLException If the prep statement fails or db doesn't exist, throws.
+ */
+ private static void loadTradeIntoDB(Trade trade) throws SQLException {
+ PreparedStatement prep = CONN.prepareStatement(
+ "INSERT into trades (stock_name, holder_name, trade_timestamp, is_buy, " +
+ "number_of_shares, holder_id) " +
+ "VALUES (?, ?, ?, ?, ?, ?)");
+
+ prep.setString(1, trade.getStock());
+ prep.setString(2, trade.getHolder().getName());
+ // TODO: update with timestamp @julia
+ prep.setDouble(3, trade.getTimestamp());
+ prep.setInt(4, trade.isBuy() ? 1 : 0);
+ prep.setInt(5, trade.getNumShares());
+ prep.setInt(6, trade.getHolder().getId());
+
+ prep.execute();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/edu/brown/cs/student/term/trade/Trade.java b/src/main/java/edu/brown/cs/student/term/trade/Trade.java
index 13f7ae1..95770e4 100644
--- a/src/main/java/edu/brown/cs/student/term/trade/Trade.java
+++ b/src/main/java/edu/brown/cs/student/term/trade/Trade.java
@@ -44,6 +44,10 @@ public class Trade {
return holder;
}
+ public int getNumShares() {
+ return numShares;
+ }
+
@Override
public String toString() {
return "Trade{" +
diff --git a/src/test/java/edu/brown/cs/student/TransactionTest.java b/src/test/java/edu/brown/cs/student/TransactionTest.java
new file mode 100644
index 0000000..f9a00f7
--- /dev/null
+++ b/src/test/java/edu/brown/cs/student/TransactionTest.java
@@ -0,0 +1,96 @@
+package edu.brown.cs.student;
+
+import edu.brown.cs.student.term.parsing.LocalXmlParser;
+import edu.brown.cs.student.term.parsing.Transaction;
+import edu.brown.cs.student.term.parsing.XmlParser;
+import edu.brown.cs.student.term.trade.Trade;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import static org.junit.Assert.*;
+
+public class TransactionTest {
+ private XmlParser _xmlParser;
+ private Document _doc;
+
+ @Before
+ public void setUp() {
+ _xmlParser = new LocalXmlParser();
+ }
+
+ @After
+ public void tearDown() {
+ _xmlParser = null;
+ }
+
+ @Test
+ public void singleTrade(){
+ setUp();
+ Document doc = _xmlParser.parse("data/xml_single_trade_test.xml");
+ assertNotEquals(doc, null);
+
+ // One trades in transaction
+ Transaction transaction = new Transaction(doc);
+ assertEquals(transaction.getTrades().size(), 1);
+
+ // TODO: add more qualities on trade to test...
+ Trade firstTrade = transaction.getTrades().get(0);
+ assertEquals(firstTrade.getNumShares(), 8236);
+
+ tearDown();
+ }
+
+ @Test
+ public void multipleTrades(){
+ setUp();
+ Document doc = _xmlParser.parse("data/xml_multiple_trades_test.xml");
+ assertNotEquals(doc, null);
+
+ // Three trades in transaction
+ Transaction transaction = new Transaction(doc);
+ assertEquals(transaction.getTrades().size(), 3);
+
+ Trade firstTrade = transaction.getTrades().get(0);
+ assertEquals(firstTrade.getNumShares(), 3000);
+
+ Trade secondTrade = transaction.getTrades().get(1);
+ assertEquals(secondTrade.getNumShares(), 3000);
+
+ Trade lastTrade = transaction.getTrades().get(2);
+ assertEquals(lastTrade.getNumShares(), 2000);
+
+ tearDown();
+ }
+
+ /*
+ @Test
+ public void derivativeTransaction(){
+ setUp();
+ Document doc = _xmlParser.parse("data/xml_derivative_only_test.xml");
+ assertNotEquals(doc, null);
+
+ // One trades in transaction
+ Transaction transaction = new Transaction(doc);
+ assertEquals(transaction.getTrades().size(), 1);
+
+ // TODO: add more qualities on trade to test...
+ Trade firstTrade = transaction.getTrades().get(0);
+ assertEquals(firstTrade.getNumShares(), 8236);
+ assertEquals(firstTrade.getHolder().getId(), 1463126);
+
+ tearDown();
+ }
+ */
+
+ @Test
+ public void noTrades(){
+ setUp();
+ // TODO: add case, but won't realistically come up
+ tearDown();
+ }
+}
diff --git a/src/test/java/edu/brown/cs/student/XmlParserTest.java b/src/test/java/edu/brown/cs/student/XmlParserTest.java
new file mode 100644
index 0000000..684452b
--- /dev/null
+++ b/src/test/java/edu/brown/cs/student/XmlParserTest.java
@@ -0,0 +1,168 @@
+package edu.brown.cs.student;
+
+import edu.brown.cs.student.term.parsing.LocalXmlParser;
+import edu.brown.cs.student.term.parsing.UrlXmlParser;
+import edu.brown.cs.student.term.parsing.XmlParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.print.Doc;
+
+import static org.junit.Assert.*;
+
+public class XmlParserTest {
+ private XmlParser _localXmlParser, _urlXmlParser;
+ private Document _doc;
+
+ @Before
+ public void setUp() {
+ _localXmlParser = new LocalXmlParser();
+ _urlXmlParser = new UrlXmlParser();
+ }
+
+ @After
+ public void tearDown() {
+ _localXmlParser = null;
+ _urlXmlParser = null;
+ }
+
+ @Test
+ public void parsesLocal(){
+ setUp();
+ Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml");
+ assertNotNull(doc);
+
+ // Id of person
+ assertEquals(getIdFromDoc(doc), "0001561844");
+ tearDown();
+ }
+
+ @Test
+ public void parsesUrl(){
+ setUp();
+ Document doc =
+ _urlXmlParser.parse("https://www.sec.gov/Archives/edgar/data/1517006/000110465921046242/tm2112036-4_4seq1.xml");
+ assertNotNull(doc);
+
+ // Id of person
+ assertEquals(getIdFromDoc(doc), "0001561844");
+ tearDown();
+ }
+
+ public String getIdFromDoc(Document doc) {
+ // Id of person
+ NodeList idNode = doc.getElementsByTagName("rptOwnerCik");
+ assertEquals(idNode.getLength(), 1);
+ return idNode.item(0).getTextContent();
+ }
+
+ @Test
+ public void urlSameAsLocal(){
+ setUp();
+ Document local = _localXmlParser.parse("data/xml_single_trade_test.xml");
+ Document url =
+ _urlXmlParser.parse("https://www.sec.gov/Archives/edgar/data/1517006/000110465921046242/tm2112036-4_4seq1.xml");
+
+ assertEquals(getIdFromDoc(local), getIdFromDoc(url));
+ tearDown();
+ }
+
+ @Test
+ public void noFileExists(){
+ setUp();
+ tearDown();
+ }
+
+ @Test
+ public void badXmlFormat(){
+ setUp();
+ Document doc = _localXmlParser.parse("data/bad.xml");
+ assertNull(doc);
+ tearDown();
+ }
+
+ @Test
+ public void personDataParse(){
+ setUp();
+ Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml");
+ assertNotNull(doc);
+
+ // Id of person
+ NodeList idNode = doc.getElementsByTagName("rptOwnerCik");
+ assertEquals(idNode.getLength(), 1);
+ String id = idNode.item(0).getTextContent();
+ assertEquals(id, "0001561844");
+
+ // Name of person
+ NodeList nameNode = doc.getElementsByTagName("rptOwnerName");
+ assertEquals(nameNode.getLength(), 1);
+ String name = nameNode.item(0).getTextContent();
+ assertEquals(name, "Levental Igor");
+
+ tearDown();
+ }
+
+ @Test
+ public void securityDataParse(){
+ setUp();
+ Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml");
+ assertNotNull(doc);
+
+ // Ticker of security
+ NodeList idNode = doc.getElementsByTagName("issuerTradingSymbol");
+ assertEquals(idNode.getLength(), 1);
+ String id = idNode.item(0).getTextContent();
+ assertEquals(id, "GATO");
+
+ tearDown();
+ }
+
+ @Test
+ public void tradeDataParse(){
+ setUp();
+ Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml");
+ assertNotEquals(doc, null);
+
+ // Data of trade in an array of values
+ NodeList trade = doc.getElementsByTagName("nonDerivativeTransaction");
+ assertEquals(trade.item(0).getNodeType(), Node.ELEMENT_NODE);
+ Element tradeElement = (Element) trade.item(0);
+ NodeList values = tradeElement.getElementsByTagName("value");
+ assertEquals(values.getLength(), 7);
+
+ // type of stock
+ String stockType = values.item(0).getTextContent();
+ assertEquals(stockType, "Common Stock");
+
+ // date
+ String date = values.item(1).getTextContent();
+ assertEquals(date, "2021-03-31");
+
+ // # of shares
+ String numShares = values.item(2).getTextContent();
+ assertEquals(numShares, "8236");
+
+ // price of shares
+ String priceShares = values.item(3).getTextContent();
+ assertEquals(priceShares, "0");
+
+ // transaction type (A for acquire)
+ String transactionType = values.item(4).getTextContent();
+ assertEquals(transactionType, "A");
+
+ // shared after transaction
+ String sharesAfter = values.item(5).getTextContent();
+ assertEquals(sharesAfter, "10799");
+
+ // ownership type
+ String ownershipType = values.item(6).getTextContent();
+ assertEquals(ownershipType, "D");
+
+ tearDown();
+ }
+}