From afd767bf26c6853c36178e2fc0d091ba1b598fea Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Mon, 5 Apr 2021 14:35:49 -0400 Subject: Added a basic xml parser that deals with local files. TODO: add a url one. Also, added some tests to ensure it's ok. Needs some edge case testing still. --- .../cs/student/term/parsing/LocalXmlParser.java | 38 ++++++++++++++++++++++ .../cs/student/term/parsing/UrlXmlParser.java | 2 ++ .../brown/cs/student/term/parsing/XmlParser.java | 37 +++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 src/main/java/edu/brown/cs/student/term/parsing/LocalXmlParser.java create mode 100644 src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java create mode 100644 src/main/java/edu/brown/cs/student/term/parsing/XmlParser.java (limited to 'src/main/java/edu') 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/UrlXmlParser.java b/src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java new file mode 100644 index 0000000..adad835 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/parsing/UrlXmlParser.java @@ -0,0 +1,2 @@ +package edu.brown.cs.student.term.parsing;public class UrlXmlParser { +} 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); +} -- cgit v1.2.3-70-g09d2 From 12498969cb903c03ff45c191e88ce3adb6146623 Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Mon, 5 Apr 2021 14:36:31 -0400 Subject: Moved around and added some tests and added an xml parser that uses urls instead of locally held files. --- ...rm-project-cohwille-jmccaul3-mfoiani-rhunt2.iml | 34 ++++++++ data/bad.xml | 7 ++ .../cs/student/term/parsing/UrlXmlParser.java | 37 ++++++++- src/test/java/edu/brown/cs/student/TradeTest.java | 93 +++++++++++++++++++++- 4 files changed, 169 insertions(+), 2 deletions(-) (limited to 'src/main/java/edu') diff --git a/.idea/term-project-cohwille-jmccaul3-mfoiani-rhunt2.iml b/.idea/term-project-cohwille-jmccaul3-mfoiani-rhunt2.iml index d9f2955..b723815 100644 --- a/.idea/term-project-cohwille-jmccaul3-mfoiani-rhunt2.iml +++ b/.idea/term-project-cohwille-jmccaul3-mfoiani-rhunt2.iml @@ -50,5 +50,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/bad.xml b/data/bad.xml index e69de29..8f17d10 100644 --- a/data/bad.xml +++ b/data/bad.xml @@ -0,0 +1,7 @@ +2021-03-31 + +0 + + +0001517006 +Gatos Silver, Inc. Date: Fri, 9 Apr 2021 16:10:30 -0400 Subject: Added functionality that adds to the DB directly. Also, can handle multiple trades within a transaction now. --- data/xml_multiple_trades_test.xml | 174 +++++++++++++++++++++ data/xml_single_trade_test.xml | 111 +++++++++++++ data/xml_trade_test.xml | 111 ------------- .../brown/cs/student/term/parsing/Transaction.java | 159 +++++++++++++++++++ .../cs/student/term/repl/commands/LoadCommand.java | 76 +++++++++ .../edu/brown/cs/student/term/trade/Trade.java | 4 + src/test/java/edu/brown/cs/student/TradeTest.java | 93 ----------- .../java/edu/brown/cs/student/TransactionTest.java | 108 +++++++++++++ .../java/edu/brown/cs/student/XmlParserTest.java | 4 +- 9 files changed, 634 insertions(+), 206 deletions(-) create mode 100644 data/xml_multiple_trades_test.xml create mode 100644 data/xml_single_trade_test.xml delete mode 100644 data/xml_trade_test.xml create mode 100644 src/main/java/edu/brown/cs/student/term/parsing/Transaction.java create mode 100644 src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java delete mode 100644 src/test/java/edu/brown/cs/student/TradeTest.java create mode 100644 src/test/java/edu/brown/cs/student/TransactionTest.java (limited to 'src/main/java/edu') diff --git a/data/xml_multiple_trades_test.xml b/data/xml_multiple_trades_test.xml new file mode 100644 index 0000000..89904e6 --- /dev/null +++ b/data/xml_multiple_trades_test.xml @@ -0,0 +1,174 @@ + + + + X0306 + + 4 + + 2021-03-24 + + 0 + + + 0000066418 + MEXCO ENERGY CORP + MXC + + + + + 0001250054 + YANKO DONNA GAIL + + + 4109 DEVON DRIVE + + EDMOND + TX + 73034 + + + + 0 + 1 + 0 + 0 + VICE PRESIDENT + + + + + + + + MXC COMMON STOCK + + + 2021-03-24 + + + + 4 + S + 0 + + + + + 3000 + + + 8.20 + + + D + + + + + 7668 + + + + + D + + + + + + MXC COMMON STOCK + + + 2021-03-30 + + + + 4 + S + 0 + + + + + 3000 + + + 8.40 + + + D + + + + + 4668 + + + + + D + + + + + + MXC COMMON STOCK + + + 2021-04-01 + + + + 4 + S + 0 + + + + + 2000 + + + 9.00 + + + D + + + + + 2668 + + + + + D + + + + + + MXC COMMON STOCK + + + + 944 + + + + + I + + + OWNED BY SPOUSE + + + + + + + /s/ D. Gail Yanko + 2021-04-05 + + diff --git a/data/xml_single_trade_test.xml b/data/xml_single_trade_test.xml new file mode 100644 index 0000000..9bd5b1b --- /dev/null +++ b/data/xml_single_trade_test.xml @@ -0,0 +1,111 @@ + + + + X0306 + + 4 + + 2021-03-31 + + 0 + + + 0001517006 + Gatos Silver, Inc. + GATO + + + + + 0001561844 + Levental Igor + + + C/O GATOS SILVER, INC., + 8400 E. CRESCENT PARKWAY, SUITE 600 + GREENWOOD VILLAGE + CO + 80111 + + + + 1 + 0 + 0 + 0 + + + + + + + + + Common Stock + + + 2021-03-31 + + + + 4 + A + 0 + + + + + 8236 + + + + 0 + + + A + + + + + 10799 + + + + + + D + + + + + + Common Stock + + + + 97363 + + + + + I + + + By Levental Family Trust + + + + + + + + Consists entirely of deferred stock units ("DSUs"), which were fully vested on the grant date. Each DSU entitles the holder to receive one share of the Company's common stock upon departure from the Company. + Includes 10,799 DSUs, which were fully vested on the date of grant. + The reporting person disclaims beneficial ownership of these shares except to the extent of his pecuniary interest. + + + + /s/ Roger Johnson, Attorney-in-Fact for Igor Levental + 2021-04-02 + + diff --git a/data/xml_trade_test.xml b/data/xml_trade_test.xml deleted file mode 100644 index 9bd5b1b..0000000 --- a/data/xml_trade_test.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - X0306 - - 4 - - 2021-03-31 - - 0 - - - 0001517006 - Gatos Silver, Inc. - GATO - - - - - 0001561844 - Levental Igor - - - C/O GATOS SILVER, INC., - 8400 E. CRESCENT PARKWAY, SUITE 600 - GREENWOOD VILLAGE - CO - 80111 - - - - 1 - 0 - 0 - 0 - - - - - - - - - Common Stock - - - 2021-03-31 - - - - 4 - A - 0 - - - - - 8236 - - - - 0 - - - A - - - - - 10799 - - - - - - D - - - - - - Common Stock - - - - 97363 - - - - - I - - - By Levental Family Trust - - - - - - - - Consists entirely of deferred stock units ("DSUs"), which were fully vested on the grant date. Each DSU entitles the holder to receive one share of the Company's common stock upon departure from the Company. - Includes 10,799 DSUs, which were fully vested on the date of grant. - The reporting person disclaims beneficial ownership of these shares except to the extent of his pecuniary interest. - - - - /s/ Roger Johnson, Attorney-in-Fact for Igor Levental - 2021-04-02 - - 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..ae33b14 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java @@ -0,0 +1,159 @@ +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 trades; + private final String personName; + private final int id; + private final String ticker; + + /** + * Constructor that extracts the important info 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(); + + NodeList tradesAsNodes = document.getElementsByTagName("nonDerivativeTransaction"); + int numTrades = tradesAsNodes.getLength(); + for(int i = 0; i < numTrades; i++) { + NodeList tradeValues = getValueList(tradesAsNodes.item(0)); + + // 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 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/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/TradeTest.java b/src/test/java/edu/brown/cs/student/TradeTest.java deleted file mode 100644 index 90d656d..0000000 --- a/src/test/java/edu/brown/cs/student/TradeTest.java +++ /dev/null @@ -1,93 +0,0 @@ -package edu.brown.cs.student; - -import edu.brown.cs.student.term.parsing.LocalXmlParser; -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 static org.junit.Assert.*; - -public class TradeTest { - private XmlParser _xmlParser; - private Document _doc; - - @Before - public void setUp() { - _xmlParser = new LocalXmlParser(); - } - - @After - public void tearDown() { - _xmlParser = null; - } - - @Test - public void personDataParse(){ - setUp(); - Document doc = _xmlParser.parse("data/xml_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 tradeDataParse(){ - setUp(); - Document doc = _xmlParser.parse("data/xml_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(); - } -} 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..a5e2987 --- /dev/null +++ b/src/test/java/edu/brown/cs/student/TransactionTest.java @@ -0,0 +1,108 @@ +package edu.brown.cs.student; + +import edu.brown.cs.student.term.parsing.LocalXmlParser; +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 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 personDataParse(){ + setUp(); + Document doc = _xmlParser.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 = _xmlParser.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 = _xmlParser.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(); + } +} diff --git a/src/test/java/edu/brown/cs/student/XmlParserTest.java b/src/test/java/edu/brown/cs/student/XmlParserTest.java index d3bc4ff..5f5b7a8 100644 --- a/src/test/java/edu/brown/cs/student/XmlParserTest.java +++ b/src/test/java/edu/brown/cs/student/XmlParserTest.java @@ -34,7 +34,7 @@ public class XmlParserTest { @Test public void parsesLocal(){ setUp(); - Document doc = _localXmlParser.parse("data/xml_trade_test.xml"); + Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml"); assertNotNull(doc); // Id of person @@ -64,7 +64,7 @@ public class XmlParserTest { @Test public void urlSameAsLocal(){ setUp(); - Document local = _localXmlParser.parse("data/xml_trade_test.xml"); + 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"); -- cgit v1.2.3-70-g09d2 From fea5c5cb4cc3eb1177cbdc8adb27d254fe2f9db7 Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Fri, 9 Apr 2021 16:28:48 -0400 Subject: Added and reorganized tests, but they fail when internet is unstable or disconnected. --- .../brown/cs/student/term/parsing/Transaction.java | 2 +- .../java/edu/brown/cs/student/TransactionTest.java | 86 +++++++--------------- .../java/edu/brown/cs/student/XmlParserTest.java | 80 ++++++++++++++++++++ 3 files changed, 108 insertions(+), 60 deletions(-) (limited to 'src/main/java/edu') 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 index ae33b14..718d2a5 100644 --- a/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java +++ b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java @@ -37,7 +37,7 @@ public class Transaction { NodeList tradesAsNodes = document.getElementsByTagName("nonDerivativeTransaction"); int numTrades = tradesAsNodes.getLength(); for(int i = 0; i < numTrades; i++) { - NodeList tradeValues = getValueList(tradesAsNodes.item(0)); + NodeList tradeValues = getValueList(tradesAsNodes.item(i)); // This stages the params for the trade. // TODO: update with real timestamp diff --git a/src/test/java/edu/brown/cs/student/TransactionTest.java b/src/test/java/edu/brown/cs/student/TransactionTest.java index a5e2987..444263d 100644 --- a/src/test/java/edu/brown/cs/student/TransactionTest.java +++ b/src/test/java/edu/brown/cs/student/TransactionTest.java @@ -1,7 +1,9 @@ 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; @@ -27,82 +29,48 @@ public class TransactionTest { } @Test - public void personDataParse(){ + public void singleTrade(){ setUp(); Document doc = _xmlParser.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(); - } + assertNotEquals(doc, null); - @Test - public void securityDataParse(){ - setUp(); - Document doc = _xmlParser.parse("data/xml_single_trade_test.xml"); - assertNotNull(doc); + // One trades in transaction + Transaction transaction = new Transaction(doc); + assertEquals(transaction.getTrades().size(), 1); - // Ticker of security - NodeList idNode = doc.getElementsByTagName("issuerTradingSymbol"); - assertEquals(idNode.getLength(), 1); - String id = idNode.item(0).getTextContent(); - assertEquals(id, "GATO"); + // TODO: add more qualities on trade to test... + Trade firstTrade = transaction.getTrades().get(0); + assertEquals(firstTrade.getNumShares(), 8236); tearDown(); } @Test - public void tradeDataParse(){ + public void multipleTrades(){ setUp(); - Document doc = _xmlParser.parse("data/xml_single_trade_test.xml"); + Document doc = _xmlParser.parse("data/xml_multiple_trades_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"); + // Three trades in transaction + Transaction transaction = new Transaction(doc); + assertEquals(transaction.getTrades().size(), 3); - // price of shares - String priceShares = values.item(3).getTextContent(); - assertEquals(priceShares, "0"); + Trade firstTrade = transaction.getTrades().get(0); + assertEquals(firstTrade.getNumShares(), 3000); - // transaction type (A for acquire) - String transactionType = values.item(4).getTextContent(); - assertEquals(transactionType, "A"); + Trade secondTrade = transaction.getTrades().get(1); + assertEquals(secondTrade.getNumShares(), 3000); - // shared after transaction - String sharesAfter = values.item(5).getTextContent(); - assertEquals(sharesAfter, "10799"); + Trade lastTrade = transaction.getTrades().get(2); + assertEquals(lastTrade.getNumShares(), 2000); - // ownership type - String ownershipType = values.item(6).getTextContent(); - assertEquals(ownershipType, "D"); + 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 index 5f5b7a8..684452b 100644 --- a/src/test/java/edu/brown/cs/student/XmlParserTest.java +++ b/src/test/java/edu/brown/cs/student/XmlParserTest.java @@ -85,4 +85,84 @@ public class XmlParserTest { 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(); + } } -- cgit v1.2.3-70-g09d2 From c0b15a96c176f01a7199d3c3d107946341af3e50 Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Fri, 9 Apr 2021 16:41:57 -0400 Subject: Added a basic skeleton for derivative trades, if we dedice to look at those as well. --- data/xml_derivative_only_test.xml | 97 ++++++++++++++++++++++ .../brown/cs/student/term/parsing/Transaction.java | 16 +++- .../java/edu/brown/cs/student/TransactionTest.java | 20 +++++ 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 data/xml_derivative_only_test.xml (limited to 'src/main/java/edu') diff --git a/data/xml_derivative_only_test.xml b/data/xml_derivative_only_test.xml new file mode 100644 index 0000000..cd19564 --- /dev/null +++ b/data/xml_derivative_only_test.xml @@ -0,0 +1,97 @@ + + + + X0306 + + 4 + + 2021-04-07 + + + 0001005817 + TOMPKINS FINANCIAL CORP + TMP + + + + + 0001463126 + Fessenden Daniel J. + + + C/O TOMPKINS FINANCIAL CORPORATION + P.O. BOX 460 + ITHACA + NY + 14851 + + + + 1 + + + + + + + Phantom Stock + + + + + + 2021-04-07 + + + 4 + A + 0 + + + + + 142.275 + + + 80.8293 + + + A + + + + + + + + + + + Common Stock + + + 142.275 + + + + + 4757.199 + + + + + D + + + + + + + Each share of phantom stock is the economic equivalent of one share of common stock. Phantom stock represents deferred stock compensation under the Amended and Restated Retainer Plan for Eligible Directors of Tompkins Financial Corporation and its Wholly-Owned Subsidiaries. These shares are held in a rabbi trust pending distribution upon the occurrence of certain events specified in the Plan. The reporting person has no voting or investment power over the shares prior to such distribution. + + + + /s/Daniel J. Fessenden + 2021-04-09 + + 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 index 718d2a5..2111048 100644 --- a/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java +++ b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java @@ -22,7 +22,7 @@ public class Transaction { private final String ticker; /** - * Constructor that extracts the important info from the document. + * Constructor that represents the transaction from the document. * @param document The document parsed from the xml file. */ public Transaction(Document document) { @@ -34,7 +34,19 @@ public class Transaction { id = id(); ticker = ticker(); - NodeList tradesAsNodes = document.getElementsByTagName("nonDerivativeTransaction"); + // 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)); diff --git a/src/test/java/edu/brown/cs/student/TransactionTest.java b/src/test/java/edu/brown/cs/student/TransactionTest.java index 444263d..f9a00f7 100644 --- a/src/test/java/edu/brown/cs/student/TransactionTest.java +++ b/src/test/java/edu/brown/cs/student/TransactionTest.java @@ -67,6 +67,26 @@ public class TransactionTest { 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(); -- cgit v1.2.3-70-g09d2