Skip to content

Commit

Permalink
Merge pull request #72 from Team-40-IDATT2003/50-file-managment-system
Browse files Browse the repository at this point in the history
50 file managment system
  • Loading branch information
etsorens authored Apr 8, 2026
2 parents 3aae11d + d681d95 commit 145ed78
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 16 deletions.
1 change: 1 addition & 0 deletions .idea/checkstyle-idea.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
* Converts stock objects to/from string format for file handling.
*
* <p style ="font-weight: bold;">Responsibilities:</p>
* <ul>
* <li>Turn a valid list of stock string elements to a
* list of {@link Stock} objects.</li>
*
* <li>Turn a list of stock objects to a
* list of string elements.</li>
* </ul>
*
* <p>Used with {@link FileParser}</p>
*
* @see FileParser
* @author tohja
* @version 1.0.0
* */
public class FileConverter {

/**
* Turns a list of valid string representations
* of stock objects to a list of stock objects.
*
* @param validStocks list of string elements properly
* representing stock objects.
*
* @return {@link List<Stock>}
*
* @throws IllegalArgumentException if stock object(s) cannot be converted.
*
* */
public List<Stock> getStocksFromStrings(final List<String> validStocks) {

List<Stock> stocksFromFile = new ArrayList<>();
List<String> stockSymbols = new ArrayList<>();

validStocks.forEach(s -> {
String[] lineElements = s.split(",");
String stockSymbol = lineElements[0].trim();
String stockName = lineElements[1].trim();
BigDecimal stockPrice = new BigDecimal(lineElements[2].trim());

try {
Stock stockObject = new Stock(stockSymbol, stockName, stockPrice);
if (!stockSymbols.contains(stockSymbol)) {
stockSymbols.add(stockSymbol);
stocksFromFile.add(stockObject);
}
} catch (IllegalArgumentException e) {
System.err.println("(" + s + ") is not a valid stock! Skipping...");
}

});
return stocksFromFile;
}

/**
* Converts a list of stocks to string representations of that stock.
*
* <p>format: SYMBOL, NAME, PRICE</p>
*
* @param stocks a list of {@link Stock} objects.
*
* @return a list of string representation of the stock objects.
* */
public List<String> stocksToStrings(final List<Stock> stocks) {
ArrayList<String> stringList = new ArrayList<>();
stocks.forEach(s ->
stringList.add(s.getSymbol().trim() + "," + s.getCompany().trim()
+ "," + s.getSalesPrice().toString())
);
return stringList;
}
}
184 changes: 184 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.function.Predicate;

/**
* Class used to parse (filter) valid stocks from a .txt file.
*
* <p style ="font-weight: bold;">Responsibilities:</p>
* <ul>
* <li>Read file and return a filtered list of string elements,
* where each element represents a valid stock line.</li>
*
* <li>Write a list of string representations of stock objects
* to file, each stock separated by a line.</li>
* </ul>
*
* <p>Used with {@link FileConverter}</p>
*
* @see FileConverter
* @author tohja
* @version 1.0.0
* */
public class FileParser {

/** The path name this parser is using.*/
private final String pathName;

/**
* Rule set for validating lines and strings.
*
* <p>Uses predicates.</p>
* */
private enum ParserRuleSet {

/**
* Rule for whether string is empty or not.
* */
NOT_EMPTY(s -> !s.trim().isEmpty()),

/**
* Rule for if string is comment or not.
* */
NOT_COMMENT(s -> !s.startsWith("#")),

/**
* Rule for if line is in valid format.
* */
VALID_FORMAT(NOT_EMPTY.rule.and(NOT_COMMENT.rule)),

/**
* Rule for if string is considered a valid company symbol.
* */
VALID_CODE(s -> s.matches("[A-Z]{4}")),

/**
* Rule for if string is a valid company name.
* */
VALID_NAME(s -> s.matches(".*")),

/**
* Rule for if string can be parsed to a {@link BigDecimal} object.
* */
CAN_PARSE_TO_BIG_DECIMAL(s -> {
try {
new BigDecimal(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}),

/**
* Rule for if string is in a valid price format.
* */
VALID_PRICE_FORMAT(s -> s.matches("[^a-zA-Z]+")),

/**
* Rule for if string is a valid price.
* */
VALID_PRICE(VALID_PRICE_FORMAT.rule.and(CAN_PARSE_TO_BIG_DECIMAL.rule));

/**
* The constants' rules as predicates with input of type string.
* */
private final Predicate<String> rule;

ParserRuleSet(final Predicate<String> rule) {
this.rule = rule;
}
}

/**
* Constructor.
*
* @param pathName the file path name to read.
* */
public FileParser(final String pathName) {
this.pathName = pathName;
}

/**
* Reads the file and returns a list element of all valid stocks as strings.
*
* <p>Uses {@link BufferedReader} for opening a file stream. </p>
*
* @return {@link List<String>} object of all valid stock strings in file.
*
* @throws IOException if path cannot be read.
*
* @see Path
* */

public List<String> readFile() throws IOException {
Path path = Paths.get(pathName);
try (BufferedReader bufferedReader = Files.newBufferedReader(path)) {

List<String> allLines = bufferedReader.readAllLines();
List<String> readableLines =
allLines.stream()
.filter(ParserRuleSet.VALID_FORMAT.rule).toList();

// Valid lines (following the correct regular expressions)
return readableLines.stream().filter(s -> {
String[] parts = s.trim().split(",");

if (parts.length != 3) {
return false;
}

boolean validCode = ParserRuleSet
.VALID_CODE.rule.test(parts[0].trim());

boolean validName = ParserRuleSet
.VALID_NAME.rule.test(parts[1].trim());

boolean validPrice = ParserRuleSet
.VALID_PRICE.rule.test(parts[2].trim());

return validCode && validName && validPrice;
}).toList();

} catch (IOException e) {
throw new IOException("File parser could not parse file!");
}
}

/**
* Writes a given lists of stocks to the file.
*
* <p>Uses {@link BufferedWriter}.</p>
*
* @param stringList list of strings representing stocks in the format
* SYMBOL, NAME, PRICE
*
* @throws IOException if writing process throws error.
* */
public void writeStocksToFile(final List<String> stringList)
throws IOException {
Path path = Paths.get(pathName);

try (BufferedWriter writer = Files.newBufferedWriter(path,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND)) {

writer.newLine();

for (String line : stringList) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
throw new IOException("Error during buffered write", e);
}
}
}
21 changes: 11 additions & 10 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
import java.io.IOException;
import java.util.List;

public class Main {
static void main() {
//TIP Press <shortcut actionId="ShowIntentionActions"/> with your caret at the highlighted text
// to see how IntelliJ IDEA suggests fixing it.
IO.println(String.format("Hello and welcome!"));

for (int i = 1; i <= 5; i++) {
//TIP Press <shortcut actionId="Debug"/> to start debugging your code. We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>.
IO.println("i = " + i);
FileParser parser1 = new FileParser("src/main/resources/dummydata.txt");
FileConverter converter1 = new FileConverter();
try {
List<Stock> stocksInFile = converter1.getStocksFromStrings(parser1.readFile());
parser1.writeStocksToFile(converter1.stocksToStrings(stocksInFile));
stocksInFile.forEach(s -> System.out.println(s.getSymbol()));
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
Expand Down Expand Up @@ -50,7 +51,7 @@ public Stock(final String symbol,
*
* @return the stock symbol
*/
public String getSymbol() {
public String getSymbol() {
return symbol;
}

Expand Down Expand Up @@ -129,5 +130,4 @@ public BigDecimal getLatestPriceChange() {

return currentPrice.subtract(previousPrice);
}

}
14 changes: 14 additions & 0 deletions src/main/resources/dummydata.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#THIS IS A COMMENT.

AAPL, Apple Inc., 276.43
NVID, Nvidida Corporation, 241.591

#Above me are some valid formats.
#Below me are some invalid formats

COOLI, This is a cool name, 252.2

COOL, This is a cool name, 252.2a

AAPL,Apple Inc.,276.43
NVID,Nvidida Corporation,241.591
11 changes: 11 additions & 0 deletions src/main/resources/testStockData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#THIS IS A COMMENT.

AAPL, Apple Inc., 276.43
NVID, Nvidida Corporation, 241.591

#Above me are some valid formats.
#Below me are some invalid formats

COOLI, This is a cool name, 252.2

COOL, This is a cool name, 252.2a
Loading

0 comments on commit 145ed78

Please sign in to comment.