diff --git a/homework-g597-kirilenko/pom.xml b/homework-g597-kirilenko/pom.xml index 481d50ef5..0b4dcc2f0 100644 --- a/homework-g597-kirilenko/pom.xml +++ b/homework-g597-kirilenko/pom.xml @@ -9,6 +9,10 @@ 4.0.0 + + 1.4.2.RELEASE + + homework-g597-kirilenko @@ -24,6 +28,33 @@ 1.0.0 test + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + + + org.springframework.boot + spring-boot-starter-jdbc + ${spring.boot.version} + + + org.springframework.boot + spring-boot-starter-security + ${spring.boot.version} + + + com.zaxxer + HikariCP + 2.5.1 + + + com.h2database + h2 + 1.4.193 + + com.google.guava guava diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task1/MyCalculator.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task1/MyCalculator.java index 2e0e4c5e9..191853d20 100644 --- a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task1/MyCalculator.java +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task1/MyCalculator.java @@ -221,4 +221,4 @@ private boolean checkIncorrectExpression(String expres) { return true; } -} +} \ No newline at end of file diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDao.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDao.java new file mode 100644 index 000000000..b4a799a65 --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDao.java @@ -0,0 +1,57 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Repository; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; + +@Repository +public class BillingDao { + private static final Logger LOG = LoggerFactory.getLogger(BillingDao.class); + + @Autowired + private DataSource dataSource; + + private JdbcTemplate jdbcTemplate; + + @PostConstruct + public void postConstruct() { + jdbcTemplate = new JdbcTemplate(dataSource, false); + initSchema(); + } + + public void initSchema() { + LOG.trace("Initializing schema"); + jdbcTemplate.execute("CREATE SCHEMA IF NOT EXISTS billing"); + jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.users " + + "(username VARCHAR PRIMARY KEY, password VARCHAR, enabled BOOLEAN)"); + jdbcTemplate.update("INSERT INTO billing.users VALUES ('username', 'password', TRUE)"); + } + + + public BillingUser loadUser(String username) throws EmptyResultDataAccessException { + LOG.trace("Querying for user " + username); + return jdbcTemplate.queryForObject( + "SELECT username, password, enabled FROM billing.users WHERE username = ?", + new Object[]{username}, + new RowMapper() { + @Override + public BillingUser mapRow(ResultSet rs, int rowNum) throws SQLException { + return new BillingUser( + rs.getString("username"), + rs.getString("password"), + rs.getBoolean("enabled") + ); + } + } + ); + } +} \ No newline at end of file diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDatabaseConfiguration.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDatabaseConfiguration.java new file mode 100644 index 000000000..dda68971e --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingDatabaseConfiguration.java @@ -0,0 +1,26 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class BillingDatabaseConfiguration { + @Bean + public DataSource billingDataSource( + @Value("${ru.mipt.java2016.homework.g597.kirilenko.task4.username:}") String username, + @Value("${ru.mipt.java2016.homework.g597.kirilenko.task4.password:}") String password + ) { + HikariConfig config = new HikariConfig(); + config.setDriverClassName(org.h2.Driver.class.getName()); + String jdbcUrl = "jdbc:h2:~/task4.db"; + config.setJdbcUrl(jdbcUrl); + config.setUsername(username); + config.setPassword(password); + return new HikariDataSource(config); + } +} diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingUser.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingUser.java new file mode 100644 index 000000000..1308c8bc5 --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/BillingUser.java @@ -0,0 +1,68 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +public class BillingUser { + private final String username; + private final String password; + private final boolean enabled; + + public BillingUser(String username, String password, boolean enabled) { + if (username == null) { + throw new IllegalArgumentException("Null username is not allowed"); + } + if (password == null) { + throw new IllegalArgumentException("Null password is not allowed"); + } + this.username = username; + this.password = password; + this.enabled = enabled; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public boolean isEnabled() { + return enabled; + } + + @Override + public String toString() { + return "BillingUser{" + + "username='" + username + '\'' + + ", password='" + password + '\'' + + ", enabled=" + enabled + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BillingUser that = (BillingUser) o; + + if (enabled != that.enabled) { + return false; + } + if (!username.equals(that.username)) { + return false; + } + return password.equals(that.password); + } + + @Override + public int hashCode() { + int result = username.hashCode(); + result = 31 * result + password.hashCode(); + result = 31 * result + (enabled ? 1 : 0); + return result; + } +} diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/CalculatorController.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/CalculatorController.java new file mode 100644 index 000000000..97264b97d --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/CalculatorController.java @@ -0,0 +1,83 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +import javafx.util.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import java.util.ArrayList; + +@RestController +public class CalculatorController { + private static final Logger LOG = LoggerFactory.getLogger(CalculatorController.class); + @Autowired + private MyCalculator calculator; + + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.GET) + public String getVariable(@PathVariable String variableName) { + String result = calculator.getVariableExpression(variableName); + return result; + } + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.GET) + public String getFunction(@PathVariable String functionName) { + Pair, String> info = calculator.getFunctionInfo(functionName); + String result = info.getValue() + "&"; + for (int i = 0; i < info.getKey().size(); i++) { + result += info.getKey().get(i); + if (i != info.getKey().size() - 1) { + result += ","; + } + } + return result + "\n"; + } + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.PUT, + consumes = "text/plain", produces = "text/plain") + public void putVariable(@PathVariable String variableName, + @RequestBody String expr) throws ParsingException { + calculator.setVariableExpression(variableName, expr); + } + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.DELETE) + public void deleteVariable(@PathVariable String variableName) { + calculator.deleteVariable(variableName); + } + + @RequestMapping(path = "/variable", method = RequestMethod.GET) + public ArrayList getVariables() { + return calculator.getAllVariables(); + } + + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.PUT) + public void putFunction(@PathVariable String functionName, + @RequestParam(value = "args") ArrayList args, + @RequestBody String functionBody) throws ParsingException { + calculator.setFunction(functionName, new ArrayList<>(args), functionBody); + } + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.DELETE) + public Boolean deleteFunction(@PathVariable String functionName) { + return calculator.deleteFunction(functionName); + } + + @RequestMapping(path = "/function", method = RequestMethod.GET) + public ArrayList getFunctionsNames() { + return calculator.getAllFunctions(); + } + + @RequestMapping(path = "/ping", method = RequestMethod.GET, produces = "text/plain") + public String echo() { + return "OK\n"; + } + + @RequestMapping(path = "/eval", method = RequestMethod.POST, consumes = "text/plain", produces = "text/plain") + public String eval(@RequestBody String expression) throws ParsingException { + double result = calculator.evaluateExpression(expression); + return Double.toString(result) + "\n"; + } +} \ No newline at end of file diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MyCalculator.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MyCalculator.java new file mode 100644 index 000000000..1c25aa379 --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MyCalculator.java @@ -0,0 +1,529 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + + +import javafx.util.Pair; +import ru.mipt.java2016.homework.base.task1.Calculator; +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +import static java.lang.Math.*; + + +public class MyCalculator implements Calculator { + private Stack numbers; + private Stack operations; + + private final Map variablesExpressions = new HashMap(); + private final Map, String>> functions = new HashMap(); + + private double calculateStandardExpression(String functionName, ArrayList arguments) + throws ParsingException { + if (functionName.equals("sin")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return sin(arguments.get(0)); + } + if (functionName.equals("cos")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return cos(arguments.get(0)); + } + if (functionName.equals("tg")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return tan(arguments.get(0)); + } + if (functionName.equals("sqrt")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return sqrt(arguments.get(0)); + } + if (functionName.equals("abs")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return abs(arguments.get(0)); + } + if (functionName.equals("max")) { + if (arguments.size() != 2) { + throw new ParsingException("Incorrect expression"); + } + return max(arguments.get(0), arguments.get(1)); + } + if (functionName.equals("min")) { + if (arguments.size() != 2) { + throw new ParsingException("Incorrect expression"); + } + return min(arguments.get(0), arguments.get(1)); + } + if (functionName.equals("pow")) { + if (arguments.size() != 2) { + throw new ParsingException("Incorrect expression"); + } + return pow(arguments.get(0), arguments.get(1)); + } + if (functionName.equals("log")) { + if (arguments.size() != 2) { + throw new ParsingException("Incorrect expression"); + } + return log(arguments.get(0)) / log(arguments.get(1)); + } + if (functionName.equals("log2")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return log(arguments.get(0)) / log(2); + } + if (functionName.equals("rnd")) { + if (arguments.size() != 0) { + throw new ParsingException("Incorrect expression"); + } + return random(); + } + if (functionName.equals("sign")) { + if (arguments.size() != 1) { + throw new ParsingException("Incorrect expression"); + } + return signum(arguments.get(0)); + } + throw new ParsingException("Not standard expression."); + } + + private boolean isStandardFunction(String functionName) { + return functionName.equals("sin") || + functionName.equals("cos") || + functionName.equals("tg") || + functionName.equals("sqrt") || + functionName.equals("pow") || + functionName.equals("abs") || + functionName.equals("sign") || + functionName.equals("log") || + functionName.equals("log2") || + functionName.equals("rnd") || + functionName.equals("max") || + functionName.equals("min"); + + } + + public String getVariableExpression(String variable) { + if (!variablesExpressions.keySet().contains(variable)) { + return null; + } + return variablesExpressions.get(variable); + } + + public void setVariableExpression(String variable, String expression) { + variablesExpressions.put(variable, expression); + } + + public void deleteVariable(String variable) { + variablesExpressions.remove(variable); + } + + public ArrayList getAllVariables() { + return new ArrayList<>(variablesExpressions.keySet()); + } + + public Pair, String> getFunctionInfo(String functionName) { + return functions.get(functionName); + } + + public boolean setFunction(String functionName, ArrayList arguments, String expression) { + if (isStandardFunction(functionName)) { + return false; + } + functions.put(functionName, new Pair<>(arguments, expression)); + return true; + } + + public boolean deleteFunction(String functionName) { + if (isStandardFunction(functionName)) { + return false; + } + functions.remove(functionName); + return true; + } + + public ArrayList getAllFunctions() { + return new ArrayList<>(functions.keySet()); + } + + private boolean isDigit(char c) { + return (c >= '0' && c <= '9'); + } + + private boolean isLatinSymbol(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + private boolean isUnderscore(char c) { + return c == '_'; + } + + private boolean isOpeningBracket(char c) { + return c == '('; + } + + + private Pair getValueLexem(String expression, Integer startIndex) { + Integer firstIndex = startIndex; + while (firstIndex < expression.length() && !isUnderscore(expression.charAt(firstIndex)) && + !isLatinSymbol(expression.charAt(firstIndex))) { + firstIndex += 1; + } + if (firstIndex >= expression.length()) { + return null; + } + Integer secondIndex = firstIndex; + while (secondIndex < expression.length() && (isUnderscore(expression.charAt(secondIndex)) || + isLatinSymbol(expression.charAt(secondIndex)) || isDigit(expression.charAt(secondIndex)))) { + secondIndex += 1; + } + if (secondIndex == expression.length() || expression.charAt(secondIndex) != '(') { + return new Pair<>(firstIndex, secondIndex); + } else { + return getValueLexem(expression, secondIndex + 1); + } + } + + private Pair>, ArrayList> getFunctionLexem(String expression) { + Integer firstIndex = 0; + while (firstIndex < expression.length() && !isUnderscore(expression.charAt(firstIndex)) && + !isLatinSymbol(expression.charAt(firstIndex))) { + firstIndex += 1; + } + if (firstIndex >= expression.length()) { + return null; + } + Integer secondIndex = firstIndex; + while (secondIndex < expression.length() && (isUnderscore(expression.charAt(secondIndex)) || + isLatinSymbol(expression.charAt(secondIndex)) || isDigit(expression.charAt(secondIndex)))) { + secondIndex += 1; + } + String name = expression.substring(firstIndex, secondIndex); + Pair, Integer> arg = getArguments(expression, secondIndex); + ArrayList arguments = arg.getKey(); + Integer lastIndex = arg.getValue(); + Pair indices = new Pair<>(firstIndex, lastIndex); + return new Pair<>(new Pair<>(name, indices), arguments); + } + + private Pair, Integer> getArguments(String expression, Integer startIndex) { + ArrayList arguments = new ArrayList<>(); + Integer lastIndex = 0; + Integer balance = 1; + Integer currentIndex = startIndex + 1; + String currentArgument = ""; + while (balance != 0) { //выражение уже проверено на корректность -> exception не выбрасываем + if (expression.charAt(currentIndex) == '(') { + balance += 1; + currentArgument += expression.charAt(currentIndex); + currentIndex++; + } else if (expression.charAt(currentIndex) == ')') { + balance -= 1; + currentArgument += expression.charAt(currentIndex); + currentIndex++; + } else if (balance == 1 && expression.charAt(currentIndex) == ',') { + arguments.add(currentArgument); + currentArgument = ""; + currentIndex++; + } else { + currentArgument += expression.charAt(currentIndex); + currentIndex++; + } + } + arguments.add(currentArgument.substring(0, currentArgument.length() - 1)); + return new Pair<>(arguments, currentIndex); + } + + private Pair findArgument(String expression, String argument) { + int lastIndex = expression.indexOf(argument, 0); + if (lastIndex == -1) { + return null; + } + return new Pair<>(lastIndex, lastIndex + argument.length()); + } + + private Double evaluateFunction(String expression, ArrayList argumentsList, + ArrayList arguments) throws ParsingException { + for (int i = 0; i < argumentsList.size(); i++) { + String argument = argumentsList.get(i); + Pair argCoord = findArgument(expression, argument); + while (argCoord != null) { + expression = expression.substring(0, argCoord.getKey()) + arguments.get(i).toString() + + expression.substring(argCoord.getValue(), expression.length()); + argCoord = findArgument(expression, argument); + } + } + try { + return evaluateExpression(expression); + } catch (ParsingException e) { + throw e; + } + } + + + + public double evaluateExpression(String expression) throws ParsingException { + expression = deleteSpaces(expression); + + + try { + Pair valueLexem = getValueLexem(expression, 0); + while (valueLexem != null) { + Integer start = valueLexem.getKey(); + Integer end = valueLexem.getValue(); + String valueName = expression.substring(start, end); + String valExpr = getVariableExpression(valueName); + Double result = evaluateExpression(valExpr); + expression = expression.substring(0, start) + result.toString() + + expression.substring(end, expression.length()); + valueLexem = getValueLexem(expression, 0); + } + Pair>, ArrayList> functionLexem = + getFunctionLexem(expression); + while (functionLexem != null) { + String functionName = functionLexem.getKey().getKey(); + Integer start = functionLexem.getKey().getValue().getKey(); + Integer end = functionLexem.getKey().getValue().getValue(); + ArrayList arguments = functionLexem.getValue(); + ArrayList calculatedArguments = new ArrayList<>(); + for (int i = 0; i < arguments.size(); i++) { + calculatedArguments.add(evaluateExpression(arguments.get(i))); + } + Double result = Double.NaN; + if (isStandardFunction(functionName)) { + result = calculateStandardExpression(functionName, calculatedArguments); + } else { + Pair, String> func = getFunctionInfo(functionName); + result = evaluateFunction(func.getValue(), func.getKey(), calculatedArguments); + } + expression = expression.substring(0, start) + result.toString() + + expression.substring(end, expression.length()); + functionLexem = getFunctionLexem(expression); + } + return calculate(expression); + } catch (ParsingException p) { + throw p; + } + } + + @Override + public double calculate(String expression) throws ParsingException { + numbers = new Stack<>(); + operations = new Stack<>(); + try { + if (expression == null) { + throw new ParsingException("Incorrect expression"); + } + if (!checkForConsequentNumbers(expression)) { + throw new ParsingException("Incorrect expression"); + } + if (!checkIncorrectExpression(expression)) { + throw new ParsingException("Incorrect expression"); + } + return toRPH(expression); + } finally { + numbers = null; + operations = null; + } + + } + + private boolean checkForConsequentNumbers(String expres) { + //между любыми двумя числами должен стоять оператор (тесты вида 1 2, 1(2) + boolean opBetween = true; + boolean notString = true; + for (int i = 0; i < expres.length(); i++) { + char c = expres.charAt(i); + if (c == '*' || c == '/' || c == '+' || c == '-') { + opBetween = true; + notString = true; + } else if (Character.isDigit(c) || c == '.') { + if (notString && !opBetween) { + return false; + } + notString = false; + opBetween = false; + } else { + notString = true; + } + } + return true; + } + + private int priority(char c) { + if (c == '+' || c == '-') { + return 1; + } else if (c == '*' || c == '/') { + return 2; + } else if (c == 'M') { + return 3; + } else { + return -1; + } + } + + private void calculationOperator(char c) { + if (c == 'M') { + double a = numbers.pop(); + numbers.push(-a); + return; + } + double a = numbers.pop(); + double b = numbers.pop(); + if (c == '+') { + numbers.push(a + b); + } else if (c == '-') { + numbers.push(b - a); + } else if (c == '*') { + numbers.push(b * a); + } else if (c == '/') { + numbers.push(b / a); + } + } + + private double toRPH(String expression) throws ParsingException { + boolean isUnary = true; //перед унарным минусом стоит либо операция, либо ( + for (int i = 0; i < expression.length(); ++i) { + char c = expression.charAt(i); + if (c == '(') { + isUnary = true; + operations.push(c); + } else if (c == ')') { + //вычиляем значение в скобках + while (operations.peek() != '(') { + calculationOperator(operations.peek()); + operations.pop(); + } + isUnary = false; + //после ')' не может быть унарного минуса + operations.pop(); + + } else if (c == '+' || c == '-' || c == '*' || c == '/') { + if (isUnary && c == '-') { + c = 'M'; + } + //сначала выполняем операции с большим приоритетом + while (!operations.isEmpty() && ((c != 'M' && + priority(operations.peek()) >= priority(c)) || (c == 'M' + && priority(operations.peek()) > priority(c)))) { + calculationOperator(operations.peek()); + operations.pop(); + } + operations.push(c); + isUnary = true; + } else { + String operand = ""; + //находим десятичное число и добавляем его в вектор чисел + while (i < expression.length() && + (Character.isDigit(expression.charAt(i)) + || expression.charAt(i) == '.')) { + operand += expression.charAt(i); + i++; + } + i--; + numbers.push(Double.parseDouble(operand)); + isUnary = false; + //после числа не может стоять унарый минус + } + } + //выполняем оставшиеся операции над получившимися числами из numbers + while (!operations.isEmpty()) { + calculationOperator(operations.peek()); + operations.pop(); + } + if (numbers.size() != 1) { + throw new ParsingException("Invalid expression."); + } + return numbers.peek(); + } + + private String deleteSpaces(String expression) { + String expres = ""; + for (int i = 0; i < expression.length(); ++i) { + if (expression.charAt(i) != ' ' && expression.charAt(i) != '\t' && expression.charAt(i) != '\n') { + expres += Character.toString(expression.charAt(i)); + } + } + return expres; + } + + private boolean checkIncorrectExpression(String expres) { + int bracketResult = 0; + //выражение непусто + //на первом месте не стоят бинарные операции + //на последнем месте либо цифра, либо ')' + if (expres.length() == 0 || expres.charAt(0) == '*' + || expres.charAt(0) == '/' || expres.charAt(0) == '+' + || !(Character.isDigit(expres.charAt(expres.length() - 1)) + || expres.charAt(expres.length() - 1) == ')')) { + return false; + } + for (int i = 0; i < expres.length(); ++i) { + if (expres.charAt(i) == '(') { + bracketResult += 1; + } + if (expres.charAt(i) == ')') { + bracketResult -= 1; + } + //после оператора не стоит бинарный оператор(то есть не *, /, +) + if (expres.charAt(i) == '-' || expres.charAt(i) == '+' + || expres.charAt(i) == '/' || expres.charAt(i) == '*') { + if (i + 1 >= expres.length() || expres.charAt(i + 1) == '+' + || expres.charAt(i + 1) == '/' || expres.charAt(i + 1) == '*') { + return false; + } + } + //проверка на некорректные символы + if (!(Character.isDigit(expres.charAt(i)) || expres.charAt(i) == '.' + || expres.charAt(i) == '(' || expres.charAt(i) == ')' + || expres.charAt(i) == '+' || expres.charAt(i) == '-' || + expres.charAt(i) == '*' || expres.charAt(i) == '/')) { + return false; + } + //проверка на неотрицательный скобочный итог + if (bracketResult < 0) { + return false; + } + //*, /, + не являются бинарными операторами, то есть они не могут стоять после '(' + //также пустые скобки считаются некорретным выражением + if (expres.charAt(i) == '(') { + if (i + 1 >= expres.length() || (expres.charAt(i + 1) == '+' + || expres.charAt(i + 1) == '*' || + expres.charAt(i + 1) == '/' || expres.charAt(i + 1) == ')')) { + return false; + } + } + } + if (bracketResult != 0) { + return false; + } + //проверка на корректность десятичного выражения(в каждом числе не больше одной '.') + int dot = 0; + int i = 0; + while (i < expres.length() && dot < 2) { + if (expres.charAt(i) == '+' || expres.charAt(i) == '-' + || expres.charAt(i) == '/' || expres.charAt(i) == '*') { + dot = 0; + } + if (expres.charAt(i) == '.') { + dot += 1; + } + i++; + } + if (dot >= 2) { + return false; + } + return true; + + } +} diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MySpringApplication.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MySpringApplication.java new file mode 100644 index 000000000..19eea25ee --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/MySpringApplication.java @@ -0,0 +1,41 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * curl http://localhost:9001/eval \ + * -X POST \ + * -H "Content-Type: text/plain" \ + * -H "Authorization: Basic $(echo -n "username:password" | base64)" \ + * --data-raw "44*3+2" + */ + +@EnableAutoConfiguration +@Configuration +@ComponentScan(basePackageClasses = MySpringApplication.class) +public class MySpringApplication { + + @Bean + public MyCalculator calculator() { + return new MyCalculator(); + } + + @Bean + public EmbeddedServletContainerCustomizer customizer( + @Value("${ru.mipt.java2016.homework.g597.kirilenko.task4.httpPort:9001}") int port) { + return container -> container.setPort(port); + } + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(MySpringApplication.class); + application.setBannerMode(Banner.Mode.OFF); + application.run(args); + } +} diff --git a/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/SecurityServiceConfiguration.java b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/SecurityServiceConfiguration.java new file mode 100644 index 000000000..6f7f1d196 --- /dev/null +++ b/homework-g597-kirilenko/src/main/java/ru/mipt/java2016/homework/g597/kirilenko/task4/SecurityServiceConfiguration.java @@ -0,0 +1,55 @@ +package ru.mipt.java2016.homework.g597.kirilenko.task4; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +import java.util.Collections; + +@Configuration +@EnableWebSecurity +public class SecurityServiceConfiguration extends WebSecurityConfigurerAdapter { + private static final Logger LOG = LoggerFactory.getLogger(SecurityServiceConfiguration.class); + + @Autowired + private BillingDao billingDao; + + @Override + protected void configure(HttpSecurity http) throws Exception { + LOG.info("Configuring security"); + http + .httpBasic().realmName("Calculator").and() + .formLogin().disable() + .logout().disable() + .csrf().disable() + .authorizeRequests() + .antMatchers("/**").authenticated() + .anyRequest().permitAll(); + } + + @Autowired + public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception { + LOG.info("Registering global user details service"); + auth.userDetailsService(username -> { + try { + BillingUser user = billingDao.loadUser(username); + return new User( + user.getUsername(), + user.getPassword(), + Collections.singletonList(() -> "AUTH") + ); + } catch (EmptyResultDataAccessException e) { + LOG.warn("No such user: " + username); + throw new UsernameNotFoundException(username); + } + }); + } +} diff --git a/homework-g597-kirilenko/src/test/java/ru/mipt/java2016/homework/g597/kirilenko/task4/tests.txt b/homework-g597-kirilenko/src/test/java/ru/mipt/java2016/homework/g597/kirilenko/task4/tests.txt new file mode 100644 index 000000000..c2107ab3f --- /dev/null +++ b/homework-g597-kirilenko/src/test/java/ru/mipt/java2016/homework/g597/kirilenko/task4/tests.txt @@ -0,0 +1,18 @@ + +curl http://localhost:9001/function/myfunc1?args=x,y -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "log2(x) + y" +curl http://localhost:9001/function/sum2?args=x,y -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "x+2* y" + +curl http://localhost:9001/variable/xy -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "sqrt(9)+sign(2)" +curl http://localhost:9001/variable/_2xy -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "log2(xy*sign(xy)) *2" + +curl http://localhost:9001/function/myfunc1 -X GET -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" +curl http://localhost:9001/function/sum2 -X GET -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" + +curl http://localhost:9001/function -X GET -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" +curl http://localhost:9001/variable -X GET -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" + +// Маленький +curl http://localhost:9001/eval -X POST -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "sqrt(_2xy*sqrt(16)) - sin(0)" + +// Большой тест +curl http://localhost:9001/eval -X POST -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "(sum2(myfunc1(xy, _2xy), sum2(4, sqrt(16)))*cos(0)" \ No newline at end of file