diff --git a/homework-g594-shevkunov/pom.xml b/homework-g594-shevkunov/pom.xml index cf6cbf5d1..c62bb52f4 100644 --- a/homework-g594-shevkunov/pom.xml +++ b/homework-g594-shevkunov/pom.xml @@ -12,6 +12,10 @@ homework-g594-shevkunov 1.0.0 + + 1.4.2.RELEASE + + ru.mipt.java2016 @@ -29,6 +33,32 @@ guava 20.0 + + 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 + + \ No newline at end of file diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task1/PolishCalculator.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task1/PolishCalculator.java index 6778fdebc..65272ee6b 100644 --- a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task1/PolishCalculator.java +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task1/PolishCalculator.java @@ -11,7 +11,7 @@ * Evaluates a value from expressing * Created by shevkunov on 04.10.16. */ -class PolishCalculator implements Calculator { +public class PolishCalculator implements Calculator { private Stack valStack = new Stack<>(); private Stack operStack = new Stack<>(); private StringBuilder buffer = new StringBuilder(); diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDao.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDao.java new file mode 100644 index 000000000..f01caf81f --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDao.java @@ -0,0 +1,205 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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; +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.execute("CREATE TABLE IF NOT EXISTS billing.vars " + + "(variable VARCHAR PRIMARY KEY, username VARCHAR," + //TODO FOREIGN KEY + " value VARCHAR)"); + + jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.funcs " + + "(function VARCHAR, username VARCHAR," + //TODO FOREIGN KEY + "args VARCHAR, value VARCHAR)"); + + jdbcTemplate.execute("DELETE FROM billing.users WHERE username = 'username'"); + jdbcTemplate.execute("DELETE FROM billing.users WHERE username = 'sudoname'"); + jdbcTemplate.update("INSERT INTO billing.users VALUES ('username', 'password', TRUE) "); + jdbcTemplate.update("INSERT INTO billing.users VALUES ('sudoname', 'aptitude', 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") + ); + } + } + ); + } + + /** Variable functions */ + public void setVariable(String username, String variable, String value) { + LOG.trace("Setting variable " + variable + " for user " + username); + delVariable(username, variable); + String querry = "INSERT INTO billing.vars VALUES ('" + variable + "','" + username + "','" + value + "')"; + jdbcTemplate.execute(querry); + } + + public String getVariable(String username, String variable) { + LOG.trace("Getting variable " + variable + " for user " + username); + String querry = "SELECT value FROM billing.vars WHERE username = '" + + username + "' AND variable = '" + variable + "'"; + return jdbcTemplate.queryForObject( + querry, + new RowMapper() { + @Override + public String mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getString("value"); + } + } + ); + } + + public List getAllVariableNames(String username) { + LOG.trace("Getting all variables for user " + username); + String querry = "SELECT variable FROM billing.vars WHERE username = '" + username + "'"; + + List vars = new ArrayList(); + + List> rows = jdbcTemplate.queryForList(querry); + + for (Map row : rows) { + vars.add((String) row.get("variable")); + } + return vars; + } + + public Map getAllVariables(String username) { + LOG.trace("Getting all variables for user " + username); + String querry = "SELECT * FROM billing.vars WHERE username = '" + username + "'"; + + Map vars = new HashMap<>(); + + List> rows = jdbcTemplate.queryForList(querry); + for (Map row : rows) { + vars.put((String) row.get("variable"), (String) row.get("value")); + } + return vars; + } + + public void delVariable(String username, String variable) { + LOG.trace("Deletting variable " + variable + " for user " + username); // TODO check valid + String querry = "DELETE FROM billing.vars WHERE username = '" + username + + "' AND variable = '" + variable + "'"; + jdbcTemplate.execute(querry); + } + + + + /** Function functions */ + public void setFunction(String username, FunctionWrapper function) { + LOG.trace("Setting function " + function.getName() + " for user " + username); + delFunction(username, function.getName()); + String querry = "INSERT INTO billing.funcs VALUES ('" + function.getName() + + "','" + username + "','" + function.argsToString() + "','" + function.getValue() + "')"; + jdbcTemplate.execute(querry); + } + + public FunctionWrapper getFunction(String username, String function) { + LOG.trace("Getting function " + function + " for user " + username); + String querry = "SELECT * FROM billing.funcs WHERE username = '" + + username + "' AND function = '" + function + "'"; + return jdbcTemplate.queryForObject( + querry, + new RowMapper() { + @Override + public FunctionWrapper mapRow(ResultSet rs, int rowNum) throws SQLException { + return new FunctionWrapper(rs.getString("function"), + rs.getString("args"), rs.getString("value")); + } + } + ); + } + + public List getAllFunctionNames(String username) { + LOG.trace("Getting all functions for user " + username); + String querry = "SELECT function FROM billing.funcs WHERE username = '" + username + "'"; + + List vars = new ArrayList(); + + List> rows = jdbcTemplate.queryForList(querry); + + for (Map row : rows) { + vars.add((String) row.get("function")); + } + return vars; + } + + public Map getAllFunctions(String username) { + LOG.trace("Getting all functions for user " + username); + String querry = "SELECT * FROM billing.funcs WHERE username = '" + username + "'"; + + Map vars = new HashMap<>(); + + List> rows = jdbcTemplate.queryForList(querry); + for (Map row : rows) { + FunctionWrapper func = new FunctionWrapper((String) row.get("function"), + (String) row.get("args"), (String) row.get("value")); + vars.put(func.getName(), func); + } + return vars; + } + + public void delFunction(String username, String function) { + LOG.trace("Deletting function " + function + " for user " + username); // TODO check valid + String querry = "DELETE FROM billing.funcs WHERE username = '" + username + + "' AND function = '" + function + "'"; + jdbcTemplate.execute(querry); + } + + + /** Function functions */ + public boolean registerUser(String username, String password) { + LOG.trace("Registering user " + username); // TODO check valid + String querry = "SELECT COUNT(*) FROM billing.users WHERE username = '" + username + "'"; + int total = jdbcTemplate.queryForObject(querry, Integer.class); + if (total != 0) { + return false; + } + querry = "INSERT INTO billing.users VALUES ('" + username + "', '" + password + "', TRUE) "; + jdbcTemplate.execute(querry); + return true; + } +} diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDatabaseConfiguration.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDatabaseConfiguration.java new file mode 100644 index 000000000..e3e2cd883 --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingDatabaseConfiguration.java @@ -0,0 +1,26 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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.g000.lavrentyev.task4.jdbcUrl:jdbc:h2:/tmp/task4/base}") String jdbcUrl, + @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.username:}") String username, + @Value("${ru.mipt.java2016.homework.g000.lavrentyev.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-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingUser.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingUser.java new file mode 100644 index 000000000..b85caba6b --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/BillingUser.java @@ -0,0 +1,69 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/CalculatorController.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/CalculatorController.java new file mode 100644 index 000000000..17f1c847f --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/CalculatorController.java @@ -0,0 +1,201 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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.Calculator; +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +@RestController +public class CalculatorController { + private static final Logger LOG = LoggerFactory.getLogger(CalculatorController.class); + + @Autowired + private BillingDao billingDao; + + @Autowired + private Calculator calculator; + + @RequestMapping(path = "/", method = RequestMethod.GET, produces = "text/html") + public String main(Authentication authentication, @RequestParam(required = false) String name) { + if (authentication != null) { + String username = authentication.getName(); + return "Hello, " + username + ".\n"; + } else { + return "Hello, noname.\n"; + } + } + + @RequestMapping(path = "/user/{username}", method = RequestMethod.PUT, produces = "text/html") + public String userPut(Authentication authentication, @PathVariable String username, + @RequestBody String password) throws ParsingException { + String result; + try { + if (billingDao.registerUser(username, password)) { + result = "Registered."; + } else { + result = "Change username."; + } + } catch (Exception e) { + result = "Can't register this user."; + } + return result + "\n"; + } + + @RequestMapping(path = "/eval", method = RequestMethod.POST, consumes = "text/plain", produces = "text/plain") + public String evalPost(Authentication authentication, @RequestBody String expression) throws ParsingException { + String username = authentication.getName(); + LOG.debug("Evaluation request: [" + expression + "] for user: " + username); + String result; + try { + double dResult = rebuildAndCalculate(expression, billingDao.getAllVariables(username), + billingDao.getAllFunctions(username)); // TODO username + result = Double.toString(dResult); + } catch (Throwable e) { + result = e.toString(); + } + + LOG.trace("Result: " + result); + return result + "\n"; + } + + /*** Variables functions + * GET /variable/${variableName} + * + * PUT /variable/${variableName} + * variable value + * + * DELETE /variable/${variableName} + * + * GET /variable/ + * + * TODO Remove this*/ + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.GET, produces = "text/html") + public String varGet(Authentication authentication, @PathVariable String variableName) throws ParsingException { + String username = authentication.getName(); + String value; + try { + value = billingDao.getVariable(username, variableName); + } catch (Exception e) { + value = e.toString(); + } + return value + "\n"; + } + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.PUT, produces = "text/html") + public String varPut(Authentication authentication, @PathVariable String variableName, + @RequestBody String value) throws ParsingException { + String username = authentication.getName(); + String result = "OK"; + try { + value = Double.toString(rebuildAndCalculate(value, billingDao.getAllVariables(username), + billingDao.getAllFunctions(username))); + billingDao.setVariable(username, variableName, value); + } catch (ParsingException e) { + result = e.toString(); + } catch (Exception e) { + result = "Server Internal Error."; + } + return result + "\n"; + } + + @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.DELETE, produces = "text/html") + public String varDel(Authentication authentication, @PathVariable String variableName) throws ParsingException { + String username = authentication.getName(); + String result = "OK"; + try { + billingDao.delVariable(username, variableName); + } catch (Exception e) { + result = e.toString(); + } + return result + "\n"; + } + + @RequestMapping(path = "/variable/", method = RequestMethod.GET, produces = "text/html") + public String allVarGet(Authentication authentication) throws ParsingException { + String username = authentication.getName(); + List allVar = billingDao.getAllVariableNames(username); + String all = "'"; + for (Iterator i = allVar.iterator(); i.hasNext();) { + all += i.next(); + if (i.hasNext()) { + all += "', '"; + } + } + + return all + "'\n"; + } + + /*** Function functions + * GET /function/${functionName} + * + * PUT /function/${functionName}?args=${argumentsList} + * function expression + * + * DELETE /function/${functionName} + * + * GET /function/ + * + * TODO Remove this*/ + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.GET, produces = "text/html") + public String funcGet(Authentication authentication, @PathVariable String functionName) throws ParsingException { + String username = authentication.getName(); + FunctionWrapper func = billingDao.getFunction(username, functionName); + return func.toString() + "\n"; + } + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.PUT, produces = "text/html") + public String funcPut(Authentication authentication, @PathVariable String functionName, + @RequestParam(value = "args") List arguments, + @RequestBody String request) throws ParsingException { + String username = authentication.getName(); + String result = "OK"; + try { + billingDao.setFunction(username, new FunctionWrapper(functionName, arguments, request)); + } catch (Exception e) { + result = e.toString(); + } + return result + "\n"; + } + + @RequestMapping(path = "/function/{functionName}", method = RequestMethod.DELETE, produces = "text/html") + public String funcDel(Authentication authentication, @PathVariable String functionName) throws ParsingException { + String username = authentication.getName(); + String result = "OK\n"; + try { + billingDao.delFunction(username, functionName); + } catch (Exception e) { + result = "Server Internal Error.\n"; + } + return result; + } + + @RequestMapping(path = "/function/", method = RequestMethod.GET, produces = "text/html") + public String allFuncGet(Authentication authentication) throws ParsingException { + String username = authentication.getName(); + List allVar = billingDao.getAllFunctionNames(username); + String all = "'"; + for (Iterator i = allVar.iterator(); i.hasNext();) { + all += i.next(); + if (i.hasNext()) { + all += "', '"; + } + } + + return all + "'\n"; + } + + private double rebuildAndCalculate(String expression, Map variables, + Map functions) throws ParsingException { + Substitutor sub = new Substitutor(variables, functions); + return calculator.calculate(sub.substitute(expression)); + } +} diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FediqApplication.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FediqApplication.java new file mode 100644 index 000000000..19118d548 --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FediqApplication.java @@ -0,0 +1,41 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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; + +/** + * 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 = FediqApplication.class) +public class FediqApplication { + + @Bean + public Calculator calculator() { + return new ru.mipt.java2016.homework.g594.shevkunov.task1.PolishCalculator(); + } + + @Bean + public EmbeddedServletContainerCustomizer customizer( + @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.httpPort:9001}") int port) { + return container -> container.setPort(port); + } + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(FediqApplication.class); + application.setBannerMode(Banner.Mode.OFF); + application.run(args); + } +} diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FunctionWrapper.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FunctionWrapper.java new file mode 100644 index 000000000..1a10e4cd8 --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/FunctionWrapper.java @@ -0,0 +1,82 @@ +package ru.mipt.java2016.homework.g594.shevkunov.task4; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Created by shevkunov on 16.12.16. + */ +public class FunctionWrapper { + FunctionWrapper(String name, List args, String value) { + this.name = name; + this.value = value; + this.args = args; + } + + FunctionWrapper(String name, String args, String value) { + this.name = name; + this.value = value; + this.args = stringToList(args); + } + + static final char SEPARATOR = ','; + private List args; + private String name; + private String value; + + public List getArgs() { + return args; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return "Function name = [" + name + "], args = [" + argsToString() + "]" + ", value = [" + value + "]"; + } + + public String argsToString() { + return listToString(args); + } + + public static List stringToList(String s) { + List list = new ArrayList<>(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) != SEPARATOR) { + sb.append(s.charAt(i)); + } else { + list.add(sb.toString()); + sb.delete(0, sb.length()); + } + } + + if (sb.length() > 0) { + list.add(sb.toString()); + } + return list; + } + + public static String listToString(List list) { + String all = ""; + for (Iterator i = list.iterator(); i.hasNext();) { + all += i.next(); + if (i.hasNext()) { + all += ","; + } + } + return all; + } + + public static boolean isVariableChar(char ch) { + return Character.isAlphabetic(ch) || Character.isDigit(ch) || ch == '_'; + } +} diff --git a/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/SecurityServiceConfiguration.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/SecurityServiceConfiguration.java new file mode 100644 index 000000000..79eab9581 --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/SecurityServiceConfiguration.java @@ -0,0 +1,57 @@ +package ru.mipt.java2016.homework.g594.shevkunov.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/**").authenticated() + .antMatchers("/variable/**").authenticated() + .antMatchers("/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-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/Substitutor.java b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/Substitutor.java new file mode 100644 index 000000000..19ad4b19d --- /dev/null +++ b/homework-g594-shevkunov/src/main/java/ru/mipt/java2016/homework/g594/shevkunov/task4/Substitutor.java @@ -0,0 +1,133 @@ +package ru.mipt.java2016.homework.g594.shevkunov.task4; + +import ru.mipt.java2016.homework.base.task1.ParsingException; + +import java.util.List; +import java.util.Map; + +/** + * Created by shevkunov on 17.12.16. + */ +public class Substitutor { + Substitutor(Map variables, + Map functions) { + this.variables = variables; + this.functions = functions; + } + + String functionSubstitute(FunctionWrapper function, String strArgs) throws ParsingException { + List substitutions = FunctionWrapper.stringToList(strArgs); + List args = function.getArgs(); + + for (int i = 0; i < substitutions.size(); ++i) { + substitutions.set(i, substitute(substitutions.get(i))); + } + + String value = function.getValue(); + + if (substitutions.size() != args.size()) { + throw new ParsingException("Bad arguments substitution."); + } + + StringBuilder res = new StringBuilder(); + for (int i = 0; i < value.length();) { + boolean substituted = false; + for (int j = 0; j < args.size(); ++j) { + String arg = args.get(j); + boolean stringComparable = (value.length() - i >= arg.length()) && + arg.equals(value.substring(i, i + arg.length())); + if (stringComparable) { // TODO So Sloow + boolean endedAtGoodSymbol = (value.length() - i == arg.length()) || + !FunctionWrapper.isVariableChar(value.charAt(i + arg.length())); + if (endedAtGoodSymbol) { + res.append(substitutions.get(j)); + i += arg.length(); + substituted = true; + break; + } + } + + res.append(value.charAt(i)); + ++i; + } + } + + return substitute(res.toString()); + } + + String substitute(String expression) throws ParsingException { + ++level; + if (level > maximumLevel) { + level = 0; + throw new ParsingException("So deep..."); + } + StringBuilder buffer = new StringBuilder(); + StringBuilder newExpression = new StringBuilder(); + + + for (int i = 0; i < expression.length(); ++i) { + if (FunctionWrapper.isVariableChar(expression.charAt(i))) { + buffer.append(expression.charAt(i)); + } + + if (!FunctionWrapper.isVariableChar(expression.charAt(i)) || (expression.length() == i + 1)) { + String proceed = buffer.toString(); + buffer.delete(0, buffer.length()); + + if (expression.charAt(i) == '(') { + // FUNCTION + if (functions.containsKey(proceed)) { + int rPos = i + 1; + int balance = 1; + while ((rPos < expression.length()) && (balance != 0)) { + switch (expression.charAt(rPos)) { + case '(': + ++balance; + break; + case ')': + --balance; + break; + default: + } + ++rPos; + } + + if (balance == 0) { + FunctionWrapper function = functions.get(proceed); + String substituted = functionSubstitute(function, expression.substring(i + 1, rPos - 1)); + newExpression.append(" ("); + newExpression.append(substituted); + newExpression.append(") "); + } else { + throw new ParsingException("Cannot substitude a function."); + } + + i = rPos - 1; + continue; + } else { + newExpression.append(proceed); + } + } else { + // VARIABLE + if (variables.containsKey(proceed)) { + newExpression.append(variables.get(proceed)); + } else { + newExpression.append(proceed); + } + } + + if (!FunctionWrapper.isVariableChar(expression.charAt(i))) { + newExpression.append(expression.charAt(i)); + } + } + } + + --level; + return newExpression.toString(); + } + + private Map variables; + private Map functions; + private int level = 0; + private final int maximumLevel = 1000; +}