From 24e0019ea328000be48275bf1b49b1057d81f646 Mon Sep 17 00:00:00 2001 From: dmitrieva irina Date: Wed, 21 Dec 2016 21:46:36 +0300 Subject: [PATCH 1/5] 4th task NEVER TOO LATE --- homework-g597-dmitrieva/pom.xml | 38 ++ .../g597/dmitrieva/task4/BillingDao.java | 242 +++++++++++++ .../task4/BillingDatabaseConfiguration.java | 26 ++ .../g597/dmitrieva/task4/BillingUser.java | 69 ++++ .../dmitrieva/task4/CalculatorController.java | 198 +++++++++++ .../g597/dmitrieva/task4/Function.java | 59 +++ .../task4/IrinaPsinaApplication.java | 48 +++ .../task4/SecurityServiceConfiguration.java | 55 +++ .../dmitrieva/task4/StringCalculator.java | 336 ++++++++++++++++++ 9 files changed, 1071 insertions(+) create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDatabaseConfiguration.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingUser.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/SecurityServiceConfiguration.java create mode 100644 homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java diff --git a/homework-g597-dmitrieva/pom.xml b/homework-g597-dmitrieva/pom.xml index 0a9633f8b..2c755a54d 100644 --- a/homework-g597-dmitrieva/pom.xml +++ b/homework-g597-dmitrieva/pom.xml @@ -10,6 +10,12 @@ 4.0.0 homework-g597-dmitrieva + pom + 1.0.0 + + + 1.4.2.RELEASE + @@ -18,6 +24,38 @@ 1.0.0 + + net.sourceforge.jeval + jeval + 0.9.4 + + + + 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 + + ru.mipt.java2016 homework-tests diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java new file mode 100644 index 000000000..8ab230ce3 --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java @@ -0,0 +1,242 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.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.security.access.method.P; +import org.springframework.stereotype.Repository; +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@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)"); + + jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.functions" + + "(username VARCHAR, nameOfFunction VARCHAR, arguments VARCHAR, expression VARCHAR, PRIMARY KEY (username, nameOfFunction))"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sin', 'a', 'sin(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','cos', 'a', 'cos(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','tg', 'a', 'tg(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sqrt', 'a', 'sqrt(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','pow', 'm, e', 'pow(m, e)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','abs', 'a', 'abs(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sign', 'a', 'sigh(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','log', 'a, n', 'log(a, n)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'log2', 'a', 'log2(a)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'rnd', '', 'rnd()')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','max', 'a, b', 'max(a, b)')"); + jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','min', 'a, b', 'min(a,b)')"); + + jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.variables " + + "(username VARCHAR, nameOfVariable VARCHAR, valueOfVariable DOUBLE NOT NULL, PRIMARY KEY (username, nameOfVariable))"); + + } + + 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") + ); + } + } + ); + } + + public void addUser(String username, String password) { + LOG.trace("Adding user " + username); + jdbcTemplate.update("INSERT INTO billing.users VALUES ('" + username + "', '" + password + "', TRUE)"); + } + + public Double getVariable(String username, String variableName) { + return jdbcTemplate.queryForObject("SELECT username, nameOfVariable, valueOfVariable FROM billing.variables WHERE username = ? AND nameOfVariable = ?", + new Object[]{username, variableName}, + new RowMapper() { + @Override + public Double mapRow(ResultSet resultSet, int rowNum) throws SQLException { + return resultSet.getDouble("valueOfVariable"); + } + } + ); + } + + Map getVariables (String username) { + try { + return jdbcTemplate.queryForObject( + "SELECT username, nameOfVariable, valueOfVariable FROM billing.variables WHERE username = ?", + new Object[]{username}, + new RowMapper>() { + @Override + public TreeMap mapRow(ResultSet resultSet, int rowNum) throws SQLException { + TreeMap selection = new TreeMap(); + while (true) { + selection.put(resultSet.getString("nameOfVariable"), + resultSet.getDouble("valueOfVariable")); + if (!resultSet.next()) { + break; + } + } + return selection; + } + } + ); + } catch (EmptyResultDataAccessException e) { + return new TreeMap<>(); + } + } + + boolean deleteVariable(String username, String nameOfVariable) { + try { + getVariable(username, nameOfVariable); + jdbcTemplate.update("DELETE FROM billing.variables WHERE username = ? AND nameOfVariable = ?", + new Object[]{username, nameOfVariable}); + return true; + } catch (EmptyResultDataAccessException e) { + return false; + } + } + + public void addVariable(String username, String nameOfVariable, Double valueOfVariable) throws ParsingException { + try { + getVariable(username, nameOfVariable); + jdbcTemplate.update("DELETE FROM billing.variables WHERE username = ? AND nameOfVariable = ?", + new Object[]{username, nameOfVariable}); + jdbcTemplate.update("INSERT INTO billing.variables VALUES (?, ?, ?)", + new Object[]{username, nameOfVariable, valueOfVariable}); + } catch (EmptyResultDataAccessException e) { + jdbcTemplate.update("INSERT INTO billing.variables VALUES (?, ?, ?)", + new Object[]{username, nameOfVariable, valueOfVariable}); + } + } + + public Function getFunction(String username, String nameOfFunction) { + return jdbcTemplate.queryForObject( + "SELECT username, nameOfFunction, arguments, expression FROM billing.functions WHERE username = ? AND nameOfFunction = ?", + new Object[]{username, nameOfFunction}, + new RowMapper() { + @Override + public Function mapRow(ResultSet resultSet, int rowNum) throws SQLException { + String nameOfFunction = resultSet.getString("nameOfFunction"); + List arguments = Arrays.asList(resultSet.getString("arguments").split(" ")); + String expression = resultSet.getString("expression"); + return new Function(nameOfFunction, arguments, expression); + } + }); + } + + + TreeMap getFunctions(String username) { + try { + return jdbcTemplate.queryForObject("SELECT username, nameOfFunction, arguments, expression FROM billing.functions WHERE username = ?", + new Object[]{username}, + new RowMapper>() { + @Override + public TreeMap mapRow(ResultSet resultSet, int rowNum) throws SQLException { + TreeMap selection = new TreeMap(); + while (true) { + String nameOfFunction = resultSet.getString("nameOfFunction"); + List arguments = Arrays.asList(resultSet.getString("arguments").split(" ")); + String expression = resultSet.getString("expression"); + selection.put(nameOfFunction, new Function(nameOfFunction, arguments, expression)); + if (!resultSet.next()) { + break; + } + } + return selection; + } + }); + } catch (EmptyResultDataAccessException e) { + return new TreeMap<>(); + } + } + + boolean deleteFunction(String username, String nameOfFunction) { + try { + getFunction(username, nameOfFunction); + jdbcTemplate.update("DELETE FROM billing.functions WHERE username = ? AND nameOfFunction = ?", + new Object[]{username, nameOfFunction}); + return true; + } catch (EmptyResultDataAccessException e) { + return false; + } + } + + void addFunction(String username, String nameOfFunction, List arguments, String expression) { + // Заменяем в функции все вхождения переменных на их значения + int beginIndexOfVariable = 0; + int endIndexOfVariable = 0; + boolean isReadingVariable = false; + for (int i = 0; i < expression.length(); i++) { + // Нашли что-то, что начинается с буквы -- возможно, это переменная + if (Character.isLetter(expression.charAt(i)) && !isReadingVariable) { + beginIndexOfVariable = i; + isReadingVariable = true; + continue; + } + // находимся в процессе чтения переменной (если это она) + if ((Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + endIndexOfVariable = i; + continue; + } + if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + isReadingVariable = false; + String variable = expression.substring(beginIndexOfVariable, endIndexOfVariable + 1); + // Если мы нашли не переменную, а какую-то функцию, то ничего с ней делать не хотим + if (getFunctions(username).containsKey(variable)) { + continue; + } + // Получаем значение переменной + String value = getVariable(username, variable).toString(); + // Заменяем ее первое вхождение на значение + expression.replaceFirst(variable, value); + // Дальше обновляем счетчик и снова ищем какую-нибудь переменную + i = 0; + } + } + try { + getFunction(username, nameOfFunction); + jdbcTemplate.update("DELETE FROM billing.functions WHERE username = ? AND nameOfFunction = ?", + new Object[]{username, nameOfFunction}); + String stringOfArguments = String.join(" ", arguments); + jdbcTemplate.update("INSERT INTO billing.functions VALUES (?, ?, ?, ?)", + new Object[]{username, nameOfFunction, stringOfArguments, expression}); + } catch (EmptyResultDataAccessException e) { + String stringArguments = String.join(" ", arguments); + jdbcTemplate.update("INSERT INTO billing.functions VALUES (?, ?, ?, ?)", + new Object[]{username, nameOfFunction, stringArguments, expression}); + } + } +} diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDatabaseConfiguration.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDatabaseConfiguration.java new file mode 100644 index 000000000..e72ea2ddd --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDatabaseConfiguration.java @@ -0,0 +1,26 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.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.dmitriyeva.task4.jdbcUrl:jdbc:h2:~/test}") String jdbcUrl, + @Value("${ru.mipt.java2016.homework.g597.dmitriyeva.task4.username:}") String username, + @Value("${ru.mipt.java2016.homework.g597.dmitriyeva.task4.password:}") String password + ) { + HikariConfig config = new HikariConfig(); + config.setDriverClassName(org.h2.Driver.class.getName()); + config.setJdbcUrl(jdbcUrl); + config.setUsername(username); + config.setPassword(password); + return new HikariDataSource(config); + } +} diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingUser.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingUser.java new file mode 100644 index 000000000..a5db16883 --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingUser.java @@ -0,0 +1,69 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.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-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java new file mode 100644 index 000000000..e5c4f77eb --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java @@ -0,0 +1,198 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.task4; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +@RestController +public class CalculatorController { + private static final Logger LOG = LoggerFactory.getLogger(CalculatorController.class); + @Autowired + private StringCalculator calculator; + + @Autowired + public BillingDao billingDao; + + @RequestMapping(path = "/ping", method = RequestMethod.GET, produces = "text/plain") + public String echo() { + return "DRATUTI\n"; + } + + @RequestMapping(path = "/", method = RequestMethod.GET, produces = "text/html") + public String main(@RequestParam(required = false) String name) { + if (name == null) { + name = "world"; + } + return "" + "IrinaPsinaApp" + "

Hello, " + name + "!

" + ""; + } + + /* + * Получить выражение, обозначенное переменной с указанным именем. + */ + @RequestMapping(path = "/variable/{nameOfVariable}", method = RequestMethod.GET, produces = "text/plain") + public String getVariable(Authentication authentication, @PathVariable String nameOfVariable) { + String ourName = authentication.getName(); + Double result = billingDao.getVariable(ourName, nameOfVariable); + return nameOfVariable + " = " + result + "\n"; + } + + /* + * Получить список имен всех переменных в сервисе. + */ + @RequestMapping(path = "/variable", method = RequestMethod.GET, produces = "text/plain") + public String getVariables(Authentication authentication) throws ParsingException { + String username = authentication.getName(); + Map result = billingDao.getVariables(username); + return String.join(", ", result.keySet()) + "\n" + ""; + } + + /* + * Удалить переменную с заданным именем. + */ + @RequestMapping(path = "/variable/{nameOfVariable}", method = RequestMethod.DELETE, produces = "text/plain") + public String deleteVariable(Authentication authentication, @PathVariable String nameOfVariable) { + String username = authentication.getName(); + boolean deleteSucceeded = billingDao.deleteVariable(username, nameOfVariable); + if (deleteSucceeded) { + return nameOfVariable + " has been deleted\n"; + } else { + return nameOfVariable + " does not exists\n"; + } + } + + /* + * Присвоить переменной новое выражение. + */ + + @RequestMapping(path = "/variable/{varName}", method = RequestMethod.PUT, consumes = "*/*;charset=UTF-8", produces = "text/plain") + public String addVariable(Authentication authentication, @PathVariable String varName, @RequestBody String valueOfVariable) throws ParsingException { + String username = authentication.getName(); + billingDao.addVariable(username, varName, Double.parseDouble(valueOfVariable)); + return "Variable " + varName + " has been added\n"; + } + + + /* + * Получить выражение, обозначенное функцией с указанным именем. + * Также возвращает список аргументов функции. Нельзя получить выражение для предопределенных функций. + */ + + @RequestMapping(path = "/function/{nameOfFunction}", method = RequestMethod.GET, produces = "text/plain") + public String getFunction(Authentication authentication, @PathVariable String nameOfFunction) { + String username = authentication.getName(); + Function result = billingDao.getFunction(username, nameOfFunction); + return nameOfFunction + "(" + String.join(", ", result.getArguments()) + ")" + " = " + result.getExpression() + "\n"; + } + + /* + * Удалить функцию с заданным именем. Предопределенные функции нельзя удалить. + */ + @RequestMapping(path = "/function/{nameOfFunction}", method = RequestMethod.DELETE, produces = "text/plain") + public String deleteFunction(Authentication authentication, @PathVariable String nameOfFunction) { + String username = authentication.getName(); + boolean success = billingDao.deleteFunction(username, nameOfFunction); + if (success) { + return nameOfFunction + " has been deleted\n"; + } else { + return nameOfFunction + " does not exists\n"; + } + } + + /* + * Присвоить функции с заданным именем следующее выражение и список аргументов. + * Предопределенные функции нельзя изменить. + */ + + //@RequestMapping(path = "/function/{nameOfFunction}", method = RequestMethod.PUT, consumes = "*/*;charset=UTF-8", produces = "text/plain") + /*public String addFunction(Authentication authentication, @PathVariable String nameOfFunction, + @RequestParam(value = "args") String args, + @RequestBody String expression) { + System.out.println("HELLO!!!!!!!!"); + String username = authentication.getName(); + List arguments = Arrays.asList(args.split(",")); + billingDao.addFunction(username, nameOfFunction, arguments, expression); + return "Function" + nameOfFunction + " has been added\n"; + } */ + + @RequestMapping(path = "/function/{name}", method = RequestMethod.PUT, + consumes = "text/plain", produces = "text/plain") + public String addFunction(Authentication authentication, @PathVariable String name, + @RequestParam(value = "args") String args, + @RequestBody String expression) + throws ParsingException { + String username = authentication.getName(); + List arguments = Arrays.asList(args.split(",")); + billingDao.addFunction(username, name, arguments, expression); + return "Function" + name + "has been added\n"; + } + + /* + * Получить список имен всех пользовательских функций в сервисе. + */ + @RequestMapping(path = "/function", method = RequestMethod.GET, produces = "text/plain") + public String getFunctions(Authentication authentication) throws ParsingException { + String username = authentication.getName(); + TreeMap map1 = billingDao.getFunctions("username"); + TreeMap map2 = billingDao.getFunctions(username); + TreeMap result = new TreeMap(); + result.putAll(map1); + result.putAll(map2); + return String.join(", ", result.keySet()) + "\n"; + } + + + /* + * Рассчитать значение выражения. + */ + @RequestMapping(path = "/eval", method = RequestMethod.POST, consumes = "*/*;charset=UTF-8", produces = "text/plain") + public String eval(Authentication authentication, @RequestBody String expression) throws ParsingException { + try { + LOG.debug("Evaluation request: [" + expression + "]"); + TreeMap AllFunctionsMap = billingDao.getFunctions(authentication.getName()); + int beginIndexOfVariable = 0; + int endIndexOfVariable = 0; + boolean isReadingVariable = false; + for (int i = 0; i < expression.length(); i++) { + // Нашли что-то, что начинается с буквы -- возможно, это переменная + if (Character.isLetter(expression.charAt(i)) && !isReadingVariable) { + beginIndexOfVariable = i; + isReadingVariable = true; + continue; + } + // находимся в процессе чтения переменной (если это она) + if ((Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + endIndexOfVariable = i; + continue; + } + if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + isReadingVariable = false; + String variable = expression.substring(beginIndexOfVariable, endIndexOfVariable + 1); + // Если мы нашли не переменную, а какую-то функцию, то ничего с ней делать не хотим + if (AllFunctionsMap.containsKey(variable)) { + continue; + } + // Получаем значение переменной + String value = billingDao.getVariable(authentication.getName(), variable).toString(); + // Заменяем ее первое вхождение на значение + expression = expression.replaceFirst(variable, value); + // Дальше обновляем счетчик и снова ищем какую-нибудь переменную + i = 0; + } + } + double result = calculator.calculateWithFunctions(expression, AllFunctionsMap); + //double result = calculator.calculate(expression); + LOG.trace("Result: " + result); + return Double.toString(result) + "\n"; + } catch (ParsingException e) { + throw new IllegalArgumentException("OSTANOVIS', POKA OSTANOVKA NE BUDET POSLEDNEY\n"); + } + } +} diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java new file mode 100644 index 000000000..a46cbd630 --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java @@ -0,0 +1,59 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.task4; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Created by irinadmitrieva on 21.12.16. + */ +public class Function { + public static final Map PREDEFINED_FUNCTIONS; + + static { + PREDEFINED_FUNCTIONS = new TreeMap<>(); + PREDEFINED_FUNCTIONS.put("sin", 1); + PREDEFINED_FUNCTIONS.put("cos", 1); + PREDEFINED_FUNCTIONS.put("tg", 1); + PREDEFINED_FUNCTIONS.put("sqrt", 1); + PREDEFINED_FUNCTIONS.put("pow", 2); + PREDEFINED_FUNCTIONS.put("abs", 1); + PREDEFINED_FUNCTIONS.put("sign", 1); + PREDEFINED_FUNCTIONS.put("log", 1); + PREDEFINED_FUNCTIONS.put("log2", 1); + PREDEFINED_FUNCTIONS.put("rnd", 1); + PREDEFINED_FUNCTIONS.put("max", 2); + PREDEFINED_FUNCTIONS.put("min", 2); + } + + private List arguments = new ArrayList<>(); + private String name; + private String expression; + private int numberOfArguments; + + public Function(String name, List arguments, String expression) { + this.name = name; + this.arguments = arguments; + this.expression = expression; + numberOfArguments = arguments.size(); + } + + private Function(String name, int numberOfArguments) { + this.name = name; + this.numberOfArguments = numberOfArguments; + this.arguments = new ArrayList<>(); + for (int i = 0; i < numberOfArguments; i++) { + arguments.add("x" + Integer.toString(i)); + } + this.expression = null; + } + + public List getArguments() { + return arguments; + } + + public String getExpression() { + return expression; + } +} \ No newline at end of file diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java new file mode 100644 index 000000000..bbaf7f159 --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java @@ -0,0 +1,48 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.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; +import ru.mipt.java2016.homework.base.task1.Calculator; +import ru.mipt.java2016.homework.g597.dmitrieva.task1.StackCalculator; +//import ru.mipt.java2016.homework.g597.dmitrieva.task1.StringCalculator; + +import java.util.Stack; + +/** + * 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" + */ + +/* curl http://localhost:9001/variable/azaz -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "1488" +*/ +@EnableAutoConfiguration +@Configuration +@ComponentScan(basePackageClasses = IrinaPsinaApplication.class) +public class IrinaPsinaApplication { + + @Bean + public StringCalculator calculator() { + return new StringCalculator(); + } + + @Bean + public EmbeddedServletContainerCustomizer customizer( + @Value("${ru.mipt.java2016.homework.g597.dmitriyeva.task4.httpPort:9001}") int port) { + return container -> container.setPort(port); + } + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(IrinaPsinaApplication.class); + application.setBannerMode(Banner.Mode.OFF); + application.run(args); + } +} diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/SecurityServiceConfiguration.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/SecurityServiceConfiguration.java new file mode 100644 index 000000000..f0fb0e413 --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/SecurityServiceConfiguration.java @@ -0,0 +1,55 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.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("/eval/**", "/variable/**", "/function/**").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-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java new file mode 100644 index 000000000..71967a89f --- /dev/null +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java @@ -0,0 +1,336 @@ +package ru.mipt.java2016.homework.g597.dmitrieva.task4; + + +import ru.mipt.java2016.homework.base.task1.Calculator; +import ru.mipt.java2016.homework.base.task1.ParsingException; +import ru.mipt.java2016.homework.g597.dmitrieva.task4.Function; + +import java.util.*; + +/** + * Created by macbook on 10.10.16. + */ + +public class StringCalculator implements Calculator { + + + private final Set SYMBOLS = + new TreeSet<>(Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.')); + private final static Set OPERATORS = new TreeSet<>(Arrays.asList("+", "-", "*", "/")); + private static Map PREDEFINED_FUNCTIONS; + + static { + PREDEFINED_FUNCTIONS = new HashMap<>(); + PREDEFINED_FUNCTIONS.put("sin", 1); + PREDEFINED_FUNCTIONS.put("cos", 1); + PREDEFINED_FUNCTIONS.put("tg", 1); + PREDEFINED_FUNCTIONS.put("sqrt", 1); + PREDEFINED_FUNCTIONS.put("pow", 2); + PREDEFINED_FUNCTIONS.put("abs", 1); + PREDEFINED_FUNCTIONS.put("sign", 1); + PREDEFINED_FUNCTIONS.put("log", 1); + PREDEFINED_FUNCTIONS.put("log2", 1); + PREDEFINED_FUNCTIONS.put("rnd", 0); + PREDEFINED_FUNCTIONS.put("max", 2); + PREDEFINED_FUNCTIONS.put("min", 2); + } + + public TreeMap ALLFUNCTIONS = new TreeMap<>(); + + + @Override + public double calculate(String expression) + throws ParsingException { + if (expression == null) { + throw new ParsingException("The string doesn't exist"); + } + return calculateReversedPolish(toReversedPolish(expression)); + } + + public double calculateWithFunctions(String expression, TreeMap functions) + throws ParsingException { + if (expression == null) { + throw new ParsingException("The string doesn't exist"); + } + ALLFUNCTIONS = functions; + return calculateReversedPolish(toReversedPolish(expression)); + } + + // Возвращает приоритет операции + private int getPriority(String operator) throws ParsingException { + if (operator.equals("(") || operator.equals(")")) { + return 0; + } + if (operator.equals("+") || operator.equals("-")) { + return 1; + } + if (operator.equals("*")|| operator.equals("/")) { + return 2; + } + if (operator.equals("&")) { + return 3; + } + if (ALLFUNCTIONS.containsKey(operator)) { + return 3; + } + throw new ParsingException("Invalid symbol"); + } + + // Возвращает ассоциативность операции + String getAssociativity(String operator) throws ParsingException { + if(OPERATORS.contains(operator)) { + return "left"; + } + if (ALLFUNCTIONS.keySet().contains(operator)) { + return "right"; + } + else { + throw new ParsingException("Do not know such function or operator"); + } + } + + // Переводит инфиксную запись в постфиксную. + private String toReversedPolish(String expression) throws ParsingException { + boolean isUnaryOperation = true; + StringBuilder postfixLine = + new StringBuilder(); // Арифметическое выражение в обратной нотации. + Stack stack = new Stack<>(); // Стек операторов. + stack.push("("); + if (expression.length() == 0) { + throw new ParsingException("The line is empty"); + } + for (int i = 0; i < expression.length(); i++) { + StringBuilder currentSymbol = new StringBuilder(); + currentSymbol.append(expression.charAt(i)); + + StringBuilder functionName = new StringBuilder(); + + // Если пробельный символ, то игнориурем. + if ((currentSymbol.charAt(0) == ' ') || currentSymbol.equals("\t")|| currentSymbol.equals("\n")) { + postfixLine.append(' '); + continue; + } + //Если символ является цифрой или точкой, то добавляем его к выходной строке. + if (SYMBOLS.contains(currentSymbol.charAt(0))) { + postfixLine.append(currentSymbol); + isUnaryOperation = false; + } else if (currentSymbol.charAt(0) == '(') { + // Если символ является открывающей скобкой, помещаем его в стек. + stack.push(currentSymbol.toString()); + postfixLine.append(' ').append(' '); + isUnaryOperation = true; + + //Если символ является оператором + } else { + if (OPERATORS.contains(currentSymbol.toString())) { + // Если это унарный минус + if (isUnaryOperation) { + if (currentSymbol.equals("-")) { + while (!stack.empty()) { + if (getPriority(currentSymbol.toString()) < getPriority(stack.lastElement())) { + postfixLine.append(' ').append(stack.pop()).append(' '); + } else { + break; + } + } + stack.push("&"); + postfixLine.append(' ').append(' '); + isUnaryOperation = false; + } else { + throw new ParsingException("Invalid expression"); + } + } else { // если это бинарный оператор + isUnaryOperation = true; + //то пока приоритет этого оператора меньше или равен приоритету оператора, + // находящегося на вершине стека, выталкиваем верхний элементы стека в выходную строку. + while (!stack.empty()) { + if (getPriority(currentSymbol.toString()) <= getPriority(stack.lastElement())) { + postfixLine.append(' ').append(stack.pop()).append(' '); + } else { + break; + } + } + postfixLine.append(' ').append(' '); + stack.push(currentSymbol.toString()); + } + // если встретили букву, то хотим считывать имя функции, пока можем + } else if (Character.isLetter(currentSymbol.charAt(0))) { + functionName.append(currentSymbol); + ++i; + currentSymbol = new StringBuilder(); + currentSymbol.append(expression.charAt(i)); + // !!!! здесь еще надо что-нибудь прикрутить на случай, если i больше длины expression + while (Character.isLetterOrDigit(currentSymbol.charAt(0)) && i < expression.length()) { + functionName.append(currentSymbol); + ++i; + currentSymbol = new StringBuilder(); + currentSymbol.append(expression.charAt(i)); + } + if (i >= expression.length()) { + throw new ParsingException("Out of range of expression"); + } + // следующим за именем функции символом должна быть открывающая скобка, иначе -- некорретное выражение + if (currentSymbol.charAt(0) == '(') { + stack.push(currentSymbol.toString()); + postfixLine.append(' ').append(' '); + isUnaryOperation = true; + } else { + throw new ParsingException("Invalid expression, couldn't find its arguments"); + } + + if (!ALLFUNCTIONS.containsKey(functionName.toString())) { + throw new ParsingException("Do not have such function"); + } + //пока приоритет этого оператора меньше приоритета оператора, + // находящегося на вершине стека, выталкиваем верхний элементы стека в выходную строку. + while (!stack.empty()) { + if (getPriority(functionName.toString()) < getPriority(stack.lastElement())) { + postfixLine.append(' ').append(stack.pop()).append(' '); + } else { + break; + } + } + postfixLine.append(' ').append(' '); + stack.push(functionName.toString()); + } else if (currentSymbol.charAt(0) == ')') { + // Если символ является закрывающей скобкой: до тех пор, пока верхним элементом + // стека не станет открывающая скобка,выталкиваем элементы из стека в выходную строку. + isUnaryOperation = false; + while (!stack.empty() && !(stack.lastElement().equals("("))) { + postfixLine.append(' '); + postfixLine.append(stack.pop()).append(' '); + } + // Если в стеке не осталось открывающейся скобки + // то в выражении не согласованы скобки. + if (stack.empty()) { + throw new ParsingException("Invalid expression"); + } + stack.pop(); // Убираем из стека соответствующую открывающую скобку. + postfixLine.append(' ').append(' '); + } else { + throw new ParsingException("Invalid symbol"); + } + } + } + // Когда входная строка закончилась, выталкиваем все символы из стека в выходную строку. + while (!(stack.lastElement().equals("(")) && !stack.empty()) { + postfixLine.append(' '); + postfixLine.append(stack.lastElement()).append(' '); + stack.pop(); + } + postfixLine.append(' '); + // Если в конце стек остался пуст, то в выражении не согласованы скобки + // (ибо в начале мы в стек пихали одну открывающую скобку, которая должна была остаться) + if (stack.empty()) { + throw new ParsingException("Invalid expression"); + } + stack.pop(); // Удалим скобку, добавленную в самом начале, если все хорошо. + return postfixLine.toString(); + } + + //Считает значение элементарного выражения. + private Double countAtomicOperation(Character operation, Double a, Double b) + throws ParsingException { + switch (operation) { + case '+': + return a + b; + case '-': + return b - a; + case '*': + return a * b; + case '/': + return b / a; + default: + throw new ParsingException("Invalid symbol"); + } + } + + // Вычисление выражения в постфиксной записи. + private double calculateReversedPolish(String postfixLine) throws ParsingException { + Stack stack = new Stack<>(); // Стек операторов. + List tokens = Arrays.asList(postfixLine.split(" ")); + //StringBuilder oneNumber = new StringBuilder(""); // Для считывания числа из постфиксной строки. + //for (int i = 0; i < tokens;) + + for (int i = 0; i < tokens.size(); i++) { + //String currentSymbol = postfixLine.charAt(i); + //StringBuilder currentSymbol = new StringBuilder() + // Здесь мы, собственно, парсим входную строку + String currentString = tokens.get(i); + if (currentString.isEmpty()) { + continue; + } + if (SYMBOLS.contains(currentString.charAt(0))) { + stack.push(Double.parseDouble(currentString)); + continue; + } + if (PREDEFINED_FUNCTIONS.containsKey(currentString)) { + // тут куча if'ов и вызов математический функций из библиотеки + continue; + } + + if (ALLFUNCTIONS.containsKey(currentString)) { + Function currentFunction = ALLFUNCTIONS.get(currentString); + String expressionForFunction = currentFunction.getExpression(); + List argumentOfFunction = currentFunction.getArguments(); + int amountOfArguments = argumentOfFunction.size(); + // проходимся по списку аргументов и делаем replace all, вместо параметров подставляем чиселски со стека + // потом делаем calculate от полученного expressiobForFunction + for (int j = amountOfArguments - 1; j >= 0; j--) { + String argument = argumentOfFunction.get(j); + Double valueOfArgument = stack.pop(); + expressionForFunction = expressionForFunction.replaceAll(argument, valueOfArgument.toString()); + } + Double resultForFunction = calculate(expressionForFunction); + stack.push(resultForFunction); + } + + if (currentString.charAt(0) == '&') { + Double a; + a = stack.pop(); + stack.push(-1 * a); + } + if (OPERATORS.contains(currentString)) { + Double a; + Double b; + a = stack.pop(); + b = stack.pop(); + stack.push(countAtomicOperation(currentString.charAt(0), a, b)); + } + + /* + if (SYMBOLS.contains(currentSymbol)) { + oneNumber.append(currentSymbol); + } else { + if (i > 0 && currentSymbol.charAt(0) == ' ' && SYMBOLS.contains(postfixLine.charAt(i - 1))) { + try { + stack.push(Double.parseDouble(oneNumber.toString())); + } catch (NumberFormatException e) { + throw new ParsingException("Bad number"); + } + oneNumber.delete(0, oneNumber.length()); + } else { + if (currentSymbol.charAt(0) == '&') { + Double a; + a = stack.pop(); + stack.push(-1 * a); + } + if (OPERATORS.contains(currentSymbol)) { + Double a; + Double b; + a = stack.pop(); + b = stack.pop(); + stack.push(countAtomicOperation(currentSymbol.charAt(0), a, b)); + } + } + } */ + } + // В конце в стеке должен был остаться один элемент, который является ответом. + if (stack.size() == 1) { + return stack.lastElement(); + } else { + // Если нет, то случилось что-то плохое + throw new ParsingException("Invalid expression"); + } + } +} \ No newline at end of file From cec8865ba2293261e2c7f32bf968323f8852bb30 Mon Sep 17 00:00:00 2001 From: dmitrieva irina Date: Wed, 21 Dec 2016 22:27:48 +0300 Subject: [PATCH 2/5] code style corrections --- .../g597/dmitrieva/task4/BillingDao.java | 60 ++++++------ .../dmitrieva/task4/CalculatorController.java | 47 +++++----- .../g597/dmitrieva/task4/Function.java | 17 ---- .../task4/IrinaPsinaApplication.java | 7 -- .../dmitrieva/task4/StringCalculator.java | 91 +++++++------------ 5 files changed, 87 insertions(+), 135 deletions(-) diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java index 8ab230ce3..3f3f95c37 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java @@ -6,7 +6,6 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; -import org.springframework.security.access.method.P; import org.springframework.stereotype.Repository; import ru.mipt.java2016.homework.base.task1.ParsingException; @@ -39,22 +38,24 @@ public void initSchema() { //jdbcTemplate.update("INSERT INTO billing.users VALUES ('username', 'password', TRUE)"); jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.functions" + - "(username VARCHAR, nameOfFunction VARCHAR, arguments VARCHAR, expression VARCHAR, PRIMARY KEY (username, nameOfFunction))"); + "(username VARCHAR, nameOfFunction VARCHAR, arguments VARCHAR, " + + "expression VARCHAR, PRIMARY KEY (username, nameOfFunction))"); //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sin', 'a', 'sin(a)')"); //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','cos', 'a', 'cos(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','tg', 'a', 'tg(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sqrt', 'a', 'sqrt(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','pow', 'm, e', 'pow(m, e)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','abs', 'a', 'abs(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sign', 'a', 'sigh(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','log', 'a, n', 'log(a, n)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'log2', 'a', 'log2(a)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'rnd', '', 'rnd()')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','max', 'a, b', 'max(a, b)')"); - jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','min', 'a, b', 'min(a,b)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','tg', 'a', 'tg(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sqrt', 'a', 'sqrt(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','pow', 'm, e', 'pow(m, e)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','abs', 'a', 'abs(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','sign', 'a', 'sigh(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','log', 'a, n', 'log(a, n)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'log2', 'a', 'log2(a)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username', 'rnd', '', 'rnd()')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','max', 'a, b', 'max(a, b)')"); + //jdbcTemplate.update("INSERT INTO billing.functions VALUES ('username','min', 'a, b', 'min(a,b)')"); jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.variables " + - "(username VARCHAR, nameOfVariable VARCHAR, valueOfVariable DOUBLE NOT NULL, PRIMARY KEY (username, nameOfVariable))"); + "(username VARCHAR, nameOfVariable VARCHAR, valueOfVariable DOUBLE NOT NULL, " + + " PRIMARY KEY (username, nameOfVariable))"); } @@ -62,7 +63,7 @@ public BillingUser loadUser(String username) throws EmptyResultDataAccessExcepti LOG.trace("Querying for user " + username); return jdbcTemplate.queryForObject( "SELECT username, password, enabled FROM billing.users WHERE username = ?", - new Object[]{username} , + new Object[]{username}, new RowMapper() { @Override public BillingUser mapRow(ResultSet rs, int rowNum) throws SQLException { @@ -82,7 +83,8 @@ public void addUser(String username, String password) { } public Double getVariable(String username, String variableName) { - return jdbcTemplate.queryForObject("SELECT username, nameOfVariable, valueOfVariable FROM billing.variables WHERE username = ? AND nameOfVariable = ?", + return jdbcTemplate.queryForObject("SELECT username, nameOfVariable, valueOfVariable " + + "FROM billing.variables WHERE username = ? AND nameOfVariable = ?", new Object[]{username, variableName}, new RowMapper() { @Override @@ -93,7 +95,7 @@ public Double mapRow(ResultSet resultSet, int rowNum) throws SQLException { ); } - Map getVariables (String username) { + Map getVariables(String username) { try { return jdbcTemplate.queryForObject( "SELECT username, nameOfVariable, valueOfVariable FROM billing.variables WHERE username = ?", @@ -144,23 +146,26 @@ public void addVariable(String username, String nameOfVariable, Double valueOfVa public Function getFunction(String username, String nameOfFunction) { return jdbcTemplate.queryForObject( - "SELECT username, nameOfFunction, arguments, expression FROM billing.functions WHERE username = ? AND nameOfFunction = ?", + "SELECT username, nameOfFunction, arguments, expression " + + "FROM billing.functions WHERE username = ? AND nameOfFunction = ?", new Object[]{username, nameOfFunction}, new RowMapper() { - @Override - public Function mapRow(ResultSet resultSet, int rowNum) throws SQLException { - String nameOfFunction = resultSet.getString("nameOfFunction"); - List arguments = Arrays.asList(resultSet.getString("arguments").split(" ")); - String expression = resultSet.getString("expression"); - return new Function(nameOfFunction, arguments, expression); - } - }); + @Override + public Function mapRow(ResultSet resultSet, int rowNum) throws SQLException { + String nameOfFunction = resultSet.getString("nameOfFunction"); + List arguments = Arrays.asList(resultSet.getString("arguments").split(" ")); + String expression = resultSet.getString("expression"); + return new Function(nameOfFunction, arguments, expression); + } + } + ); } TreeMap getFunctions(String username) { try { - return jdbcTemplate.queryForObject("SELECT username, nameOfFunction, arguments, expression FROM billing.functions WHERE username = ?", + return jdbcTemplate.queryForObject("SELECT username, nameOfFunction, arguments, expression" + + " FROM billing.functions WHERE username = ?", new Object[]{username}, new RowMapper>() { @Override @@ -211,7 +216,8 @@ void addFunction(String username, String nameOfFunction, List arguments, endIndexOfVariable = i; continue; } - if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') + && isReadingVariable) { isReadingVariable = false; String variable = expression.substring(beginIndexOfVariable, endIndexOfVariable + 1); // Если мы нашли не переменную, а какую-то функцию, то ничего с ней делать не хотим diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java index e5c4f77eb..4234e7f89 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java @@ -19,7 +19,7 @@ public class CalculatorController { private StringCalculator calculator; @Autowired - public BillingDao billingDao; + private BillingDao billingDao; @RequestMapping(path = "/ping", method = RequestMethod.GET, produces = "text/plain") public String echo() { @@ -31,7 +31,8 @@ public String main(@RequestParam(required = false) String name) { if (name == null) { name = "world"; } - return "" + "IrinaPsinaApp" + "

Hello, " + name + "!

" + ""; + return "" + "IrinaPsinaApp" + + "

Hello, " + name + "!

" + ""; } /* @@ -48,7 +49,7 @@ public String getVariable(Authentication authentication, @PathVariable String na * Получить список имен всех переменных в сервисе. */ @RequestMapping(path = "/variable", method = RequestMethod.GET, produces = "text/plain") - public String getVariables(Authentication authentication) throws ParsingException { + public String getVariables(Authentication authentication) { String username = authentication.getName(); Map result = billingDao.getVariables(username); return String.join(", ", result.keySet()) + "\n" + ""; @@ -72,8 +73,10 @@ public String deleteVariable(Authentication authentication, @PathVariable String * Присвоить переменной новое выражение. */ - @RequestMapping(path = "/variable/{varName}", method = RequestMethod.PUT, consumes = "*/*;charset=UTF-8", produces = "text/plain") - public String addVariable(Authentication authentication, @PathVariable String varName, @RequestBody String valueOfVariable) throws ParsingException { + @RequestMapping(path = "/variable/{varName}", method = RequestMethod.PUT, + consumes = "*/*;charset=UTF-8", produces = "text/plain") + public String addVariable(Authentication authentication, @PathVariable String varName, + @RequestBody String valueOfVariable) throws ParsingException { String username = authentication.getName(); billingDao.addVariable(username, varName, Double.parseDouble(valueOfVariable)); return "Variable " + varName + " has been added\n"; @@ -87,9 +90,10 @@ public String addVariable(Authentication authentication, @PathVariable String va @RequestMapping(path = "/function/{nameOfFunction}", method = RequestMethod.GET, produces = "text/plain") public String getFunction(Authentication authentication, @PathVariable String nameOfFunction) { - String username = authentication.getName(); + String username = authentication.getName(); Function result = billingDao.getFunction(username, nameOfFunction); - return nameOfFunction + "(" + String.join(", ", result.getArguments()) + ")" + " = " + result.getExpression() + "\n"; + return nameOfFunction + "(" + String.join(", ", result.getArguments()) + ")" + + " = " + result.getExpression() + "\n"; } /* @@ -110,18 +114,6 @@ public String deleteFunction(Authentication authentication, @PathVariable String * Присвоить функции с заданным именем следующее выражение и список аргументов. * Предопределенные функции нельзя изменить. */ - - //@RequestMapping(path = "/function/{nameOfFunction}", method = RequestMethod.PUT, consumes = "*/*;charset=UTF-8", produces = "text/plain") - /*public String addFunction(Authentication authentication, @PathVariable String nameOfFunction, - @RequestParam(value = "args") String args, - @RequestBody String expression) { - System.out.println("HELLO!!!!!!!!"); - String username = authentication.getName(); - List arguments = Arrays.asList(args.split(",")); - billingDao.addFunction(username, nameOfFunction, arguments, expression); - return "Function" + nameOfFunction + " has been added\n"; - } */ - @RequestMapping(path = "/function/{name}", method = RequestMethod.PUT, consumes = "text/plain", produces = "text/plain") public String addFunction(Authentication authentication, @PathVariable String name, @@ -138,7 +130,7 @@ public String addFunction(Authentication authentication, @PathVariable String na * Получить список имен всех пользовательских функций в сервисе. */ @RequestMapping(path = "/function", method = RequestMethod.GET, produces = "text/plain") - public String getFunctions(Authentication authentication) throws ParsingException { + public String getFunctions(Authentication authentication) { String username = authentication.getName(); TreeMap map1 = billingDao.getFunctions("username"); TreeMap map2 = billingDao.getFunctions(username); @@ -152,11 +144,12 @@ public String getFunctions(Authentication authentication) throws ParsingExceptio /* * Рассчитать значение выражения. */ - @RequestMapping(path = "/eval", method = RequestMethod.POST, consumes = "*/*;charset=UTF-8", produces = "text/plain") + @RequestMapping(path = "/eval", method = RequestMethod.POST, + consumes = "*/*;charset=UTF-8", produces = "text/plain") public String eval(Authentication authentication, @RequestBody String expression) throws ParsingException { try { LOG.debug("Evaluation request: [" + expression + "]"); - TreeMap AllFunctionsMap = billingDao.getFunctions(authentication.getName()); + TreeMap allFunctionsMap = billingDao.getFunctions(authentication.getName()); int beginIndexOfVariable = 0; int endIndexOfVariable = 0; boolean isReadingVariable = false; @@ -168,15 +161,17 @@ public String eval(Authentication authentication, @RequestBody String expression continue; } // находимся в процессе чтения переменной (если это она) - if ((Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + if ((Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') + && isReadingVariable) { endIndexOfVariable = i; continue; } - if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') && isReadingVariable) { + if (!(Character.isLetterOrDigit(expression.charAt(i)) || expression.charAt(i) == '_') + && isReadingVariable) { isReadingVariable = false; String variable = expression.substring(beginIndexOfVariable, endIndexOfVariable + 1); // Если мы нашли не переменную, а какую-то функцию, то ничего с ней делать не хотим - if (AllFunctionsMap.containsKey(variable)) { + if (allFunctionsMap.containsKey(variable)) { continue; } // Получаем значение переменной @@ -187,7 +182,7 @@ public String eval(Authentication authentication, @RequestBody String expression i = 0; } } - double result = calculator.calculateWithFunctions(expression, AllFunctionsMap); + double result = calculator.calculateWithFunctions(expression, allFunctionsMap); //double result = calculator.calculate(expression); LOG.trace("Result: " + result); return Double.toString(result) + "\n"; diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java index a46cbd630..49f21cb17 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java @@ -9,23 +9,6 @@ * Created by irinadmitrieva on 21.12.16. */ public class Function { - public static final Map PREDEFINED_FUNCTIONS; - - static { - PREDEFINED_FUNCTIONS = new TreeMap<>(); - PREDEFINED_FUNCTIONS.put("sin", 1); - PREDEFINED_FUNCTIONS.put("cos", 1); - PREDEFINED_FUNCTIONS.put("tg", 1); - PREDEFINED_FUNCTIONS.put("sqrt", 1); - PREDEFINED_FUNCTIONS.put("pow", 2); - PREDEFINED_FUNCTIONS.put("abs", 1); - PREDEFINED_FUNCTIONS.put("sign", 1); - PREDEFINED_FUNCTIONS.put("log", 1); - PREDEFINED_FUNCTIONS.put("log2", 1); - PREDEFINED_FUNCTIONS.put("rnd", 1); - PREDEFINED_FUNCTIONS.put("max", 2); - PREDEFINED_FUNCTIONS.put("min", 2); - } private List arguments = new ArrayList<>(); private String name; diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java index bbaf7f159..641cce47e 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/IrinaPsinaApplication.java @@ -8,11 +8,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import ru.mipt.java2016.homework.base.task1.Calculator; -import ru.mipt.java2016.homework.g597.dmitrieva.task1.StackCalculator; -//import ru.mipt.java2016.homework.g597.dmitrieva.task1.StringCalculator; - -import java.util.Stack; /** * curl http://localhost:9001/eval \ @@ -22,8 +17,6 @@ * --data-raw "44*3+2" */ -/* curl http://localhost:9001/variable/azaz -X PUT -H "Content-Type: text/plain" -H "Authorization: Basic $(echo -n "username:password" | base64)" --data-raw "1488" -*/ @EnableAutoConfiguration @Configuration @ComponentScan(basePackageClasses = IrinaPsinaApplication.class) diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java index 71967a89f..e089c0e46 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java @@ -3,7 +3,6 @@ import ru.mipt.java2016.homework.base.task1.Calculator; import ru.mipt.java2016.homework.base.task1.ParsingException; -import ru.mipt.java2016.homework.g597.dmitrieva.task4.Function; import java.util.*; @@ -13,29 +12,28 @@ public class StringCalculator implements Calculator { - - private final Set SYMBOLS = + private final static Set SYMBOLS = new TreeSet<>(Arrays.asList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.')); private final static Set OPERATORS = new TreeSet<>(Arrays.asList("+", "-", "*", "/")); - private static Map PREDEFINED_FUNCTIONS; + private static Map BaseFunctions; static { - PREDEFINED_FUNCTIONS = new HashMap<>(); - PREDEFINED_FUNCTIONS.put("sin", 1); - PREDEFINED_FUNCTIONS.put("cos", 1); - PREDEFINED_FUNCTIONS.put("tg", 1); - PREDEFINED_FUNCTIONS.put("sqrt", 1); - PREDEFINED_FUNCTIONS.put("pow", 2); - PREDEFINED_FUNCTIONS.put("abs", 1); - PREDEFINED_FUNCTIONS.put("sign", 1); - PREDEFINED_FUNCTIONS.put("log", 1); - PREDEFINED_FUNCTIONS.put("log2", 1); - PREDEFINED_FUNCTIONS.put("rnd", 0); - PREDEFINED_FUNCTIONS.put("max", 2); - PREDEFINED_FUNCTIONS.put("min", 2); + BaseFunctions = new HashMap<>(); + BaseFunctions.put("sin", 1); + BaseFunctions.put("cos", 1); + BaseFunctions.put("tg", 1); + BaseFunctions.put("sqrt", 1); + BaseFunctions.put("pow", 2); + BaseFunctions.put("abs", 1); + BaseFunctions.put("sign", 1); + BaseFunctions.put("log", 1); + BaseFunctions.put("log2", 1); + BaseFunctions.put("rnd", 0); + BaseFunctions.put("max", 2); + BaseFunctions.put("min", 2); } - public TreeMap ALLFUNCTIONS = new TreeMap<>(); + private TreeMap AllFunctions = new TreeMap<>(); @Override @@ -52,7 +50,7 @@ public double calculateWithFunctions(String expression, TreeMap= expression.length()) { throw new ParsingException("Out of range of expression"); } - // следующим за именем функции символом должна быть открывающая скобка, иначе -- некорретное выражение + // следующим за именем функции символом должна быть открывающая скобка, + // иначе -- некорретное выражение if (currentSymbol.charAt(0) == '(') { stack.push(currentSymbol.toString()); postfixLine.append(' ').append(' '); @@ -178,7 +176,7 @@ private String toReversedPolish(String expression) throws ParsingException { throw new ParsingException("Invalid expression, couldn't find its arguments"); } - if (!ALLFUNCTIONS.containsKey(functionName.toString())) { + if (!AllFunctions.containsKey(functionName.toString())) { throw new ParsingException("Do not have such function"); } //пока приоритет этого оператора меньше приоритета оператора, @@ -264,13 +262,17 @@ private double calculateReversedPolish(String postfixLine) throws ParsingExcepti stack.push(Double.parseDouble(currentString)); continue; } - if (PREDEFINED_FUNCTIONS.containsKey(currentString)) { + if (BaseFunctions.containsKey(currentString)) { + switch (currentString) { + case "sin": + + } // тут куча if'ов и вызов математический функций из библиотеки continue; } - if (ALLFUNCTIONS.containsKey(currentString)) { - Function currentFunction = ALLFUNCTIONS.get(currentString); + if (AllFunctions.containsKey(currentString)) { + Function currentFunction = AllFunctions.get(currentString); String expressionForFunction = currentFunction.getExpression(); List argumentOfFunction = currentFunction.getArguments(); int amountOfArguments = argumentOfFunction.size(); @@ -297,33 +299,6 @@ private double calculateReversedPolish(String postfixLine) throws ParsingExcepti b = stack.pop(); stack.push(countAtomicOperation(currentString.charAt(0), a, b)); } - - /* - if (SYMBOLS.contains(currentSymbol)) { - oneNumber.append(currentSymbol); - } else { - if (i > 0 && currentSymbol.charAt(0) == ' ' && SYMBOLS.contains(postfixLine.charAt(i - 1))) { - try { - stack.push(Double.parseDouble(oneNumber.toString())); - } catch (NumberFormatException e) { - throw new ParsingException("Bad number"); - } - oneNumber.delete(0, oneNumber.length()); - } else { - if (currentSymbol.charAt(0) == '&') { - Double a; - a = stack.pop(); - stack.push(-1 * a); - } - if (OPERATORS.contains(currentSymbol)) { - Double a; - Double b; - a = stack.pop(); - b = stack.pop(); - stack.push(countAtomicOperation(currentSymbol.charAt(0), a, b)); - } - } - } */ } // В конце в стеке должен был остаться один элемент, который является ответом. if (stack.size() == 1) { From 7e45c0e169eac1bd6ef68bd5374e7eb6b304a41e Mon Sep 17 00:00:00 2001 From: dmitrieva irina Date: Thu, 22 Dec 2016 00:03:27 +0300 Subject: [PATCH 3/5] Added base functions in calculator --- .../dmitrieva/task4/StringCalculator.java | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java index e089c0e46..699b1442a 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java @@ -35,7 +35,6 @@ public class StringCalculator implements Calculator { private TreeMap AllFunctions = new TreeMap<>(); - @Override public double calculate(String expression) throws ParsingException { @@ -103,7 +102,7 @@ private String toReversedPolish(String expression) throws ParsingException { StringBuilder functionName = new StringBuilder(); // Если пробельный символ, то игнориурем. - if ((currentSymbol.charAt(0) == ' ') || currentSymbol.equals("\t") || currentSymbol.equals("\n")) { + if ((currentSymbol.charAt(0) == ' ') || currentSymbol.charAt(0) == ',' ||currentSymbol.equals("\t") || currentSymbol.equals("\n")) { postfixLine.append(' '); continue; } @@ -246,14 +245,11 @@ private Double countAtomicOperation(Character operation, Double a, Double b) // Вычисление выражения в постфиксной записи. private double calculateReversedPolish(String postfixLine) throws ParsingException { Stack stack = new Stack<>(); // Стек операторов. + final Random RANDOM = new Random(); List tokens = Arrays.asList(postfixLine.split(" ")); - //StringBuilder oneNumber = new StringBuilder(""); // Для считывания числа из постфиксной строки. - //for (int i = 0; i < tokens;) for (int i = 0; i < tokens.size(); i++) { - //String currentSymbol = postfixLine.charAt(i); - //StringBuilder currentSymbol = new StringBuilder() - // Здесь мы, собственно, парсим входную строку + String currentString = tokens.get(i); if (currentString.isEmpty()) { continue; @@ -263,11 +259,65 @@ private double calculateReversedPolish(String postfixLine) throws ParsingExcepti continue; } if (BaseFunctions.containsKey(currentString)) { - switch (currentString) { - case "sin": + switch (currentString) { + case "sin": { + stack.push(Math.sin(stack.pop())); + break; + } + case "cos": { + stack.push(Math.cos(stack.pop())); + break; + } + case "tg": { + stack.push(Math.tan(stack.pop())); + break; + } + case "sqrt": { + stack.push(Math.sqrt(stack.pop())); + break; + } + case "abs": { + stack.push(Math.abs(stack.pop())); + break; + } + case "sign": { + stack.push(Math.signum(stack.pop())); + break; + } + case "log": { + // log(x)/log(y) = log_y(x) + Double x = stack.pop(); + Double y = stack.pop(); + stack.push(Math.log(x) / Math.log(y)); + break; + } + case "pow": { + Double x = stack.pop(); + Double y = stack.pop(); + stack.push(Math.pow(x, y)); + } + case "log2": { + stack.push(Math.log(stack.pop()) / Math.log(2)); + break; + } + case "rnd": { + stack.push(RANDOM.nextDouble()); + break; + } + case "max": { + Double x = stack.pop(); + Double y = stack.pop(); + stack.push(Math.max(x, y)); + break; + } + case "min": { + Double x = stack.pop(); + Double y = stack.pop(); + stack.push(Math.min(x, y)); + break; + } } - // тут куча if'ов и вызов математический функций из библиотеки continue; } From 78bbc56e6aa509ded40c3e3a7fcbb0f6f63d2152 Mon Sep 17 00:00:00 2001 From: dmitrieva irina Date: Thu, 22 Dec 2016 18:29:22 +0300 Subject: [PATCH 4/5] The mistake with replacement of variables corrected. Still need to fix up the code style. --- .../homework/g597/dmitrieva/task4/BillingDao.java | 9 ++++++++- .../g597/dmitrieva/task4/CalculatorController.java | 5 +++-- .../homework/g597/dmitrieva/task4/StringCalculator.java | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java index 3f3f95c37..77bf013ff 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/BillingDao.java @@ -208,6 +208,7 @@ void addFunction(String username, String nameOfFunction, List arguments, // Нашли что-то, что начинается с буквы -- возможно, это переменная if (Character.isLetter(expression.charAt(i)) && !isReadingVariable) { beginIndexOfVariable = i; + endIndexOfVariable = i; // ??? isReadingVariable = true; continue; } @@ -224,7 +225,13 @@ void addFunction(String username, String nameOfFunction, List arguments, if (getFunctions(username).containsKey(variable)) { continue; } - // Получаем значение переменной + // Если какую-то переменную мы нашли, но в списке переменных это пользователя ее нет, + // значит, это просто аргумент функции и можно расслабиться + if (!getVariables(username).containsKey(variable)) { + continue; + } + // Если же это действительно переменная, добавленная пользователем, + // то получаем ее значение String value = getVariable(username, variable).toString(); // Заменяем ее первое вхождение на значение expression.replaceFirst(variable, value); diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java index 4234e7f89..8d287ceb3 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/CalculatorController.java @@ -123,7 +123,7 @@ public String addFunction(Authentication authentication, @PathVariable String na String username = authentication.getName(); List arguments = Arrays.asList(args.split(",")); billingDao.addFunction(username, name, arguments, expression); - return "Function" + name + "has been added\n"; + return "Function " + name + " has been added\n"; } /* @@ -157,6 +157,7 @@ public String eval(Authentication authentication, @RequestBody String expression // Нашли что-то, что начинается с буквы -- возможно, это переменная if (Character.isLetter(expression.charAt(i)) && !isReadingVariable) { beginIndexOfVariable = i; + endIndexOfVariable = i; isReadingVariable = true; continue; } @@ -185,7 +186,7 @@ public String eval(Authentication authentication, @RequestBody String expression double result = calculator.calculateWithFunctions(expression, allFunctionsMap); //double result = calculator.calculate(expression); LOG.trace("Result: " + result); - return Double.toString(result) + "\n"; + return "The result of expression: " + expression + " has been calculated\n" + "Result: " + Double.toString(result) + "\n"; } catch (ParsingException e) { throw new IllegalArgumentException("OSTANOVIS', POKA OSTANOVKA NE BUDET POSLEDNEY\n"); } diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java index 699b1442a..609a7fdbc 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/StringCalculator.java @@ -295,7 +295,8 @@ private double calculateReversedPolish(String postfixLine) throws ParsingExcepti case "pow": { Double x = stack.pop(); Double y = stack.pop(); - stack.push(Math.pow(x, y)); + stack.push(Math.pow(y, x)); + break; } case "log2": { stack.push(Math.log(stack.pop()) / Math.log(2)); From 3b2d4cc12715315efeff8386bc9b68643ea681a1 Mon Sep 17 00:00:00 2001 From: dmitrieva irina Date: Thu, 22 Dec 2016 20:07:48 +0300 Subject: [PATCH 5/5] Deleted excess code --- .../homework/g597/dmitrieva/task4/Function.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java index 49f21cb17..a58b1560a 100644 --- a/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java +++ b/homework-g597-dmitrieva/src/main/java/ru/mipt/java2016/homework/g597/dmitrieva/task4/Function.java @@ -22,16 +22,6 @@ public Function(String name, List arguments, String expression) { numberOfArguments = arguments.size(); } - private Function(String name, int numberOfArguments) { - this.name = name; - this.numberOfArguments = numberOfArguments; - this.arguments = new ArrayList<>(); - for (int i = 0; i < numberOfArguments; i++) { - arguments.add("x" + Integer.toString(i)); - } - this.expression = null; - } - public List getArguments() { return arguments; }