diff --git a/solutions/chipak/pom.xml b/solutions/chipak/pom.xml new file mode 100644 index 0000000..4c43ee9 --- /dev/null +++ b/solutions/chipak/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + ru.fizteh.fivt.students + parent + 1.0-SNAPSHOT + + ru.fizteh.fivt.students + chipak + 1.0-SNAPSHOT + chipak + http://maven.apache.org + + UTF-8 + + + + junit + junit + 3.8.1 + + + org.twitter4j + twitter4j-stream + [4.0,) + + + com.beust + jcommander + 1.48 + + + com.h2database + h2 + 1.4.190 + + + diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/BlockingQueue.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/BlockingQueue.java new file mode 100644 index 0000000..581c169 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/BlockingQueue.java @@ -0,0 +1,106 @@ +package ru.fizteh.fivt.students.chipak.Threads; + + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class BlockingQueue { + + private Queue queue; + private int maxSize; + private final Lock lock = new ReentrantLock(); + private final Condition notEnoughSpace = lock.newCondition(); + private final Condition notEnoughElements = lock.newCondition(); + private final Object offerSynchronizer = new Object(); + private final Object takeSynchronizer = new Object(); + + BlockingQueue(int size) { + queue = new ArrayDeque(); + maxSize = size; + } + + void offer(List toAdd) throws InterruptedException { + synchronized (offerSynchronizer) { + lock.lock(); + try { + while ((queue.size() + toAdd.size()) > maxSize) { + notEnoughSpace.await(); + } + queue.addAll(toAdd); + notEnoughElements.signalAll(); + } finally { + lock.unlock(); + } + } + } + + List take(int n) throws InterruptedException { + synchronized (takeSynchronizer) { + lock.lock(); + List ans = new ArrayList(); + try { + + while (queue.size() < n) { + notEnoughElements.await(); + } + for (int i = 0; i < n; ++i) { + ans.add(queue.remove()); + } + notEnoughElements.signalAll(); + } finally { + lock.unlock(); + return ans; + } + } + } + + void offer(List toAdd, long timeout) throws InterruptedException { + synchronized (offerSynchronizer) { + lock.lock(); + long waitingTime = timeout; + final long startTime = System.currentTimeMillis(); + try { + while (queue.size() + toAdd.size() > maxSize && waitingTime > 0) { + notEnoughElements.await(waitingTime, TimeUnit.MILLISECONDS); + waitingTime = timeout - (System.currentTimeMillis() - startTime); + } + if (queue.size() + toAdd.size() <= maxSize) { + queue.addAll(toAdd); + notEnoughElements.notifyAll(); + } + } finally { + lock.unlock(); + } + } + } + + List take(int n, long timeout) throws InterruptedException { + synchronized (takeSynchronizer) { + lock.lock(); + List ans = new ArrayList(); + long waitingTime = timeout; + final long startTime = System.currentTimeMillis(); + try { + while (queue.size() < n && waitingTime > 0) { + notEnoughElements.await(waitingTime, TimeUnit.MILLISECONDS); + waitingTime = timeout - (System.currentTimeMillis() - startTime); + } + if (queue.size() >= n) { + for (int i = 0; i < n; ++i) { + ans.add(queue.remove()); + } + notEnoughElements.notifyAll(); + } + } finally { + lock.unlock(); + return ans; + } + } + } +} diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/Counter.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/Counter.java new file mode 100644 index 0000000..7129209 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/Threads/Counter.java @@ -0,0 +1,54 @@ +package ru.fizteh.fivt.students.chipak.Threads; + + + +public class Counter { + + private static volatile int currentID; + + private static Object synchronizer = new Object(); + + private static class OneCounter implements Runnable { + private int id, size; + + + OneCounter(int id, int size) { + this.id = id; + this.size = size; + } + + @Override + public void run() { + while (true) { + try { + synchronized (synchronizer) { + while (id != currentID) { + synchronizer.wait(); + } + System.out.println("Thread-" + String.valueOf(id)); + currentID++; + if (currentID > size) { + currentID %= size; + } + synchronizer.notifyAll(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public static void main(String[] args) throws IllegalArgumentException { + if (args.length != 1) { + throw new IllegalArgumentException(); + } + int n; + n = Integer.valueOf(args[0]); + currentID = 1; + for (int i = 0; i < n; i++) { + Thread oneCounter = new Thread(new OneCounter(i + 1, n)); + oneCounter.start(); + } + } +} diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Aggregates.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Aggregates.java new file mode 100644 index 0000000..cfc4af3 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Aggregates.java @@ -0,0 +1,102 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import java.util.List; +import java.util.function.Function; + + +public class Aggregates { + + + public static > Function max(Function expression) { + return new AggregationFunction() { + private Function converter = expression; + + @Override + public T apply(List list) { + T result = null; + for (C element : list) { + if (result == null) { + result = converter.apply(element); + } else { + T currentResult = converter.apply(element); + if (currentResult.compareTo(result) > 0) { + result = currentResult; + } + } + } + return result; + } + + @Override + public T apply(C c) { + return null; + } + }; + } + + + public static > Function min(Function expression) { + return new AggregationFunction() { + private Function converter = expression; + + @Override + public T apply(List list) { + T result = null; + for (C element : list) { + if (result == null) { + result = converter.apply(element); + } else { + T currentResult = converter.apply(element); + if (currentResult.compareTo(result) < 0) { + result = currentResult; + } + } + } + return result; + } + + @Override + public T apply(C c) { + return null; + } + }; + } + + + public static Function count(Function expression) { + return new AggregationFunction() { + @Override + public Integer apply(List list) { + return list.size(); + } + + @Override + public Integer apply(C c) { + return null; + } + }; + } + + + public static Function avg(Function expression) { + return new AggregationFunction() { + private Function converter = expression; + + @Override + public Double apply(List list) { + Double result = 0d; + for (C element : list) { + result += converter.apply(element).doubleValue(); + } + result /= list.size(); + return result; + } + + @Override + public Double apply(C t) { + return null; + } + }; + } + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/AggregationFunction.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/AggregationFunction.java new file mode 100644 index 0000000..27267f3 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/AggregationFunction.java @@ -0,0 +1,8 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import java.util.List; +import java.util.function.Function; + +public interface AggregationFunction extends Function { + E apply(List list); +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/CollectionQuery.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/CollectionQuery.java new file mode 100644 index 0000000..b336c26 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/CollectionQuery.java @@ -0,0 +1,145 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import ru.fizteh.fivt.students.chipak.collectionquery.impl.Tuple; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Objects; + +import static ru.fizteh.fivt.students.chipak.collectionquery.Aggregates.avg; +import static ru.fizteh.fivt.students.chipak.collectionquery.Aggregates.count; +import static ru.fizteh.fivt.students.chipak.collectionquery.CollectionQuery.Student.student; +import static ru.fizteh.fivt.students.chipak.collectionquery.Conditions.rlike; +import static ru.fizteh.fivt.students.chipak.collectionquery.OrderByConditions.asc; +import static ru.fizteh.fivt.students.chipak.collectionquery.OrderByConditions.desc; +import static ru.fizteh.fivt.students.chipak.collectionquery.Sources.list; +import static ru.fizteh.fivt.students.chipak.collectionquery.impl.FromStmt.from; + +/** + * @author akormushin + */ +public class CollectionQuery { + + /** + * Make this code work! + * + * @param args + */ + public static void main(String[] args) throws Exception { + Iterable statistics = + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1986-08-06"), "495"), + student("petrov", LocalDate.parse("2006-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) + .where(rlike(Student::getName, ".*ov").and(s -> s.age() > 20)) + .groupBy(Student::getGroup) + .having(s -> s.getCount() > 0) + .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) + .limit(100) + .union() + .from(list(student("ivanov", LocalDate.parse("1985-08-06"), "494"))) + .selectDistinct(Statistics.class, s -> "all", count(s -> 1), avg(Student::age)) + .execute(); + System.out.println(statistics); + + Iterable> mentorsByStudent = + from(list(student("ivanov", LocalDate.parse("1985-08-06"), "494"))) + .join(list(new Group("494", "mr.sidorov"))) + .on((s, g) -> Objects.equals(s.getGroup(), g.getGroup())) + .select(sg -> sg.getFirst().getName(), sg -> sg.getSecond().getMentor()) + .execute(); + System.out.println(mentorsByStudent); + } + + + public static class Student { + private final String name; + + private final LocalDate dateOfBith; + + private final String group; + + public String getName() { + return name; + } + + public Student(String name, LocalDate dateOfBith, String group) { + this.name = name; + this.dateOfBith = dateOfBith; + this.group = group; + } + + public LocalDate getDateOfBith() { + return dateOfBith; + } + + public String getGroup() { + return group; + } + + public long age() { + return ChronoUnit.YEARS.between(getDateOfBith(), LocalDateTime.now()); + } + + public static Student student(String name, LocalDate dateOfBith, String group) { + return new Student(name, dateOfBith, group); + } + } + + public static class Group { + private final String group; + private final String mentor; + + public Group(String group, String mentor) { + this.group = group; + this.mentor = mentor; + } + + public String getGroup() { + return group; + } + + public String getMentor() { + return mentor; + } + } + + + public static class Statistics { + + private final String group; + private final Integer count; + private final Double age; + + public String getGroup() { + return group; + } + + public Integer getCount() { + return count; + } + + public Double getAge() { + return age; + } + + public Statistics(String group, Integer count, Double age) { + this.group = group; + this.count = count; + this.age = age; + } + + @Override + public String toString() { + return "Statistics{" + + "group='" + group + '\'' + + ", count=" + count + + ", age=" + age + + '}'; + } + } + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Conditions.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Conditions.java new file mode 100644 index 0000000..39eab30 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Conditions.java @@ -0,0 +1,37 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Where clause conditions. + * + * @author akormushin + */ +public class Conditions { + + /** + * Matches string result of expression against regexp pattern. + * + * @param expression expression result to match + * @param regexp pattern to match to + * @param source object type + * @return + */ + public static Predicate rlike(Function expression, String regexp) { + return (object) -> (expression.apply(object).matches(regexp)); + } + + /** + * Matches string result of expression against SQL like pattern. + * + * @param expression expression result to match + * @param pattern pattern to match to + * @param source object type + * @return + */ + public static Predicate like(Function expression, String pattern) { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/OrderByConditions.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/OrderByConditions.java new file mode 100644 index 0000000..67c262d --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/OrderByConditions.java @@ -0,0 +1,37 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import java.util.Comparator; +import java.util.function.Function; + +/** + * OrderBy sort order helper methods. + * + * @author akormushin + */ +public class OrderByConditions { + + /** + * Ascending comparator. + * + * @param expression + * @param + * @param + * @return + */ + public static > Comparator asc(Function expression) { + return (o1, o2) -> expression.apply(o1).compareTo(expression.apply(o2)); + } + + /** + * Descending comparator. + * + * @param expression + * @param + * @param + * @return + */ + public static > Comparator desc(Function expression) { + return (o1, o2) -> expression.apply(o2).compareTo(expression.apply(o1)); + } + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Sources.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Sources.java new file mode 100644 index 0000000..633838a --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/Sources.java @@ -0,0 +1,56 @@ +package ru.fizteh.fivt.students.chipak.collectionquery; + +import java.io.InputStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Helper methods to create collections. + * + * @author akormushin + */ +public class Sources { + + /** + * @param items + * @param + * @return + */ + @SafeVarargs + public static List list(T... items) { + return new ArrayList<>(Arrays.asList(items)); + } + + /** + * @param items + * @param + * @return + */ + @SafeVarargs + public static Set set(T... items) { + throw new UnsupportedOperationException(); + } + + /** + * @param inputStream + * @param + * @return + */ + public static Stream lines(InputStream inputStream) { + throw new UnsupportedOperationException(); + } + + /** + * @param file + * @param + * @return + */ + public static Stream lines(Path file) { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/FromStmt.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/FromStmt.java new file mode 100644 index 0000000..434952a --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/FromStmt.java @@ -0,0 +1,158 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +import com.beust.jcommander.internal.Lists; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class FromStmt { + private List previousResult; + private List elements; + + + public FromStmt(Iterable iterable) { + elements = StreamSupport.stream(iterable.spliterator(), false). + collect(Collectors.toList()); + } + + public FromStmt(Stream stream) { + elements = stream.collect(Collectors.toList()); + } + + public void setPreviousResult(List previousResult) { + this.previousResult = previousResult; + } + + + public static FromStmt from(Iterable iterable) { + return new FromStmt(iterable); + } + + public static FromStmt from(Stream stream) { + return new FromStmt(stream); + } + + public static FromStmt from(Query query) throws + ReflectiveOperationException { + return new FromStmt(query.execute()); + } + + @SafeVarargs + public final SelectStmt select(Class clazz, Function... s) { + return new SelectStmt<>(previousResult, elements, clazz, false, s); + } + + /** + * Selects the only defined expression as is without wrapper. + * + * @param s + * @param + * @return statement resulting in collection of R + */ + public final SelectStmt select(Function s) { + return new SelectStmt<>(previousResult, elements, false, s); + } + + /** + * Selects the only defined expression as is without wrapper. + * + * @param first + * @param second + * @param + * @param + * @return statement resulting in collection of R + */ + public final SelectStmt> select(Function first, Function second) { + Function> converter = (element) -> (new Tuple<>(first.apply(element), + second.apply(element))); + return new SelectStmt<>(previousResult, elements, false, converter); + } + + @SafeVarargs + public final SelectStmt selectDistinct(Class clazz, Function... s) { + return new SelectStmt(previousResult, elements, clazz, true, s); + } + + /** + * Selects the only defined expression as is without wrapper. + * + * @param s + * @param + * @return statement resulting in collection of R + */ + public final SelectStmt selectDistinct(Function s) { + return new SelectStmt(previousResult, elements, true, s); + } + + /////////////////////////////////////////////////////////////////////////// + + public JoinClause join(Iterable iterable) { + return new JoinClause<>(this, StreamSupport.stream(iterable.spliterator(), false). + collect(Collectors.toList())); + } + + public JoinClause join(Stream stream) { + return new JoinClause<>(this, stream.collect(Collectors.toList())); + } + + public JoinClause join(Query stream) throws ReflectiveOperationException { + return new JoinClause<>(this, + StreamSupport.stream(stream.execute().spliterator(), false). + collect(Collectors.toList())); + } + + public class JoinClause { + private FromStmt fromStmt; + private List extraSource; + + public JoinClause(FromStmt fromStmt, List extraSource) { + this.fromStmt = fromStmt; + this.extraSource = extraSource; + } + + public FromStmt> on(BiPredicate condition) { + List> sourceForFrom = new ArrayList<>(); + for (T firstElement : fromStmt.elements) { + for (J secondElement : extraSource) { + if (condition.test(firstElement, secondElement)) { + sourceForFrom.add(new Tuple<>(firstElement, secondElement)); + } + } + } + FromStmt> newFrom = new FromStmt>(sourceForFrom); + newFrom.setPreviousResult(fromStmt.previousResult); + return newFrom; + } + + public > FromStmt> on( + Function leftKey, + Function rightKey) { + Map> mapForFirstSource = new HashMap<>(); + List> sourceForFrom = new ArrayList<>(); + for (T element : fromStmt.elements) { + if (mapForFirstSource.containsKey(leftKey.apply(element))) { + mapForFirstSource.get(leftKey.apply(element)).add(element); + } else { + mapForFirstSource.put(leftKey.apply(element), Lists.newArrayList(element)); + } + } + extraSource.stream().filter(element -> mapForFirstSource. + containsKey(rightKey.apply(element))).forEach(element -> { + sourceForFrom.addAll(mapForFirstSource. + get(rightKey.apply(element)).stream(). + map(firstElement -> new Tuple<>(firstElement, element)). + collect(Collectors.toList())); + }); + FromStmt> newFrom = new FromStmt<>(sourceForFrom); + newFrom.setPreviousResult(fromStmt.previousResult); + return newFrom; + } + } +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/GroupByResult.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/GroupByResult.java new file mode 100644 index 0000000..574a77e --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/GroupByResult.java @@ -0,0 +1,40 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +import java.util.function.Function; + +public class GroupByResult { + private Object[] results; + + public GroupByResult(T element, Function[] functions) { + results = new Object[functions.length]; + for (int i = 0; i < functions.length; ++i) { + results[i] = functions[i].apply(element); + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GroupByResult)) { + return false; + } + GroupByResult anotherResult = (GroupByResult) obj; + if (results.length != anotherResult.results.length) { + return false; + } + for (int i = 0; i < results.length; ++i) { + if (!results[i].equals(anotherResult.results[i])) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + int ans = 0; + for (Object element : results) { + ans += element.hashCode(); + } + return ans; + } +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Query.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Query.java new file mode 100644 index 0000000..9736e7a --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Query.java @@ -0,0 +1,11 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +import java.util.stream.Stream; + + +public interface Query { + + Iterable execute() throws ReflectiveOperationException; + + Stream stream() throws ReflectiveOperationException; +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/SelectStmt.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/SelectStmt.java new file mode 100644 index 0000000..3698a39 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/SelectStmt.java @@ -0,0 +1,254 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +import ru.fizteh.fivt.students.chipak.collectionquery.AggregationFunction; + +import java.lang.reflect.Constructor; +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + + +public class SelectStmt implements Query { + private List source; + private boolean isDistinct; + private boolean hasConvertingFunction; + private Function converter; + private Function[] functions; + private Class rClass; + private List previousResult; + + @SafeVarargs + public SelectStmt(List previousResult, List source, Class rClass, + boolean isDistinct, Function... functions) { + this.functions = functions; + hasConvertingFunction = false; + this.converter = null; + this.isDistinct = isDistinct; + this.source = source; + this.rClass = rClass; + this.previousResult = previousResult; + } + + public SelectStmt(List previousResult, List source, boolean isDistinct, + Function s) { + this.source = source; + hasConvertingFunction = true; + this.isDistinct = isDistinct; + this.converter = s; + this.functions = null; + this.previousResult = previousResult; + } + + + public WhereStmt where(Predicate predicate) { + return new WhereStmt<>(source, predicate, isDistinct, hasConvertingFunction, + converter, functions, rClass); + } + + @Override + public Iterable execute() throws ReflectiveOperationException { + return new WhereStmt(source, element -> true, isDistinct, + hasConvertingFunction, converter, functions, rClass).execute(); + + } + + @Override + public Stream stream() throws ReflectiveOperationException { + return StreamSupport.stream(execute().spliterator(), false); + } + + + public class WhereStmt implements Query { + + private List source; + private Predicate wherePredicate; + private Function[] groupByExpressions; + private Comparator[] orderByComparators; + private Predicate havingPredicate; + private boolean isDistinct; + private boolean hasConvertingFunction; + private Function converter; + private Function[] functions; + private Class rClass; + private int limit = -1; + + public WhereStmt(List source, Predicate wherePredicate, boolean isDistinct, + boolean hasConvertingFunction, Function converter, + Function[] functions, Class rClass) { + this.source = source; + this.wherePredicate = wherePredicate; + this.isDistinct = isDistinct; + this.hasConvertingFunction = hasConvertingFunction; + this.converter = converter; + this.functions = functions; + this.rClass = rClass; + } + + @SafeVarargs + public final WhereStmt groupBy(Function... expressions) { + groupByExpressions = expressions; + return this; + } + + @SafeVarargs + public final WhereStmt orderBy(Comparator... comparators) { + orderByComparators = comparators; + return this; + } + + public WhereStmt having(Predicate condition) { + havingPredicate = condition; + return this; + } + + public WhereStmt limit(int amount) { + if (amount < 0) { + throw new IllegalArgumentException("limit < 0"); + } + limit = amount; + return this; + } + + public UnionStmt union() throws ReflectiveOperationException { + return new UnionStmt(StreamSupport.stream(execute().spliterator(), false) + .collect(Collectors.toList())); + } + + @Override + public Iterable execute() throws ReflectiveOperationException { + List> result = new ArrayList<>(); + if (wherePredicate != null) { + source = source.stream().filter(wherePredicate::test).collect(Collectors.toList()); + } + if (groupByExpressions != null) { + List> groupedSource = new ArrayList<>(); + Map, Integer> mapOfResultWithNumber = new HashMap<>(); + Map> mapOfElementWithResult = new HashMap<>(); + for (T element : source) { + GroupByResult resultForElement = new GroupByResult<>(element, groupByExpressions); + mapOfElementWithResult.put(element, resultForElement); + if (!mapOfResultWithNumber.containsKey(resultForElement)) { + mapOfResultWithNumber.put(resultForElement, mapOfResultWithNumber.size()); + } + } + for (int i = 0; i < mapOfResultWithNumber.size(); ++i) { + groupedSource.add(new ArrayList<>()); + } + for (T element : source) { + groupedSource.get(mapOfResultWithNumber.get(mapOfElementWithResult.get(element))). + add(element); + } + for (List source : groupedSource) { + result.add(executeOnList(source)); + } + } else { + result.add(executeOnList(source)); + } + if (havingPredicate != null) { + List> newResult = new ArrayList<>(); + for (List element : result) { + newResult.add(element.stream().filter(havingPredicate::test). + collect(Collectors.toList())); + } + result = newResult; + } + if (orderByComparators != null) { + for (List list : result) { + list.sort(compileComparator(orderByComparators)); + } + } + List ans = new ArrayList<>(); + for (List element : result) { + ans.addAll(element); + } + if (limit >= 0) { + ans = ans.subList(0, Math.min(ans.size(), limit)); + } + if (previousResult != null) { + if (previousResult.size() > 0) { + if (rClass != null && previousResult.get(0).getClass() != rClass + || ans.size() > 0 + && previousResult.get(0).getClass() != ans.get(0).getClass()) { + throw new IllegalArgumentException("Can't call union"); + } else { + List newAns = (List) previousResult; + newAns.addAll(ans); + ans = newAns; + } + } + } + + return ans; + } + + private Comparator compileComparator(Comparator[] orderByComparators) { + return (first, second) -> { + for (int i = 0; i < orderByComparators.length - 1; ++i) { + if (orderByComparators[i].compare(first, second) != 0) { + return orderByComparators[i].compare(first, second); + } + } + return orderByComparators[orderByComparators.length - 1].compare(first, second); + }; + } + + @Override + public Stream stream() throws ReflectiveOperationException { + return StreamSupport.stream(execute().spliterator(), false); + } + + private List executeOnList(List currentSource) throws ReflectiveOperationException { + List result = new ArrayList<>(); + if (hasConvertingFunction) { + for (T element : currentSource) { + result.add(converter.apply(element)); + } + } else { + List> temporaryResults; + temporaryResults = new ArrayList<>(); + for (int i = 0; i < currentSource.size(); ++i) { + temporaryResults.add(new ArrayList<>(functions.length)); + } + for (Function function : functions) { + if (function instanceof AggregationFunction) { + Object resultOfFunction = ((AggregationFunction) function).apply(currentSource); + for (int j = 0; j < currentSource.size(); ++j) { + temporaryResults.get(j).add(resultOfFunction); + } + } else { + for (int j = 0; j < currentSource.size(); ++j) { + temporaryResults.get(j).add(function.apply(currentSource.get(j))); + } + } + } + for (List objects : temporaryResults) { + Class[] classes = new Class[functions.length]; + for (int i = 0; i < functions.length; ++i) { + classes[i] = temporaryResults.get(0).get(i).getClass(); + } + Constructor constructor = rClass.getConstructor(classes); + result.add(constructor.newInstance(objects.toArray())); + } + } + if (isDistinct) { + result = getDistinctResult(result); + } + return result; + } + + private List getDistinctResult(List result) { + Set uniqueElements = new HashSet<>(); + List uniqueResults = new ArrayList<>(); + for (R element : result) { + if (!uniqueElements.contains(element)) { + uniqueResults.add(element); + uniqueElements.add(element); + } + } + return uniqueResults; + } + } +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Tuple.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Tuple.java new file mode 100644 index 0000000..b1894a1 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/Tuple.java @@ -0,0 +1,31 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +/** + * @author akormushin + */ +public class Tuple { + + private final F first; + private final S second; + + public Tuple(F first, S second) { + this.first = first; + this.second = second; + } + + public F getFirst() { + return first; + } + + public S getSecond() { + return second; + } + + @Override + public String toString() { + return "Tuple{" + + "first=" + first + + ", second=" + second + + '}'; + } +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/UnionStmt.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/UnionStmt.java new file mode 100644 index 0000000..6b1d8e4 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/collectionquery/impl/UnionStmt.java @@ -0,0 +1,22 @@ +package ru.fizteh.fivt.students.chipak.collectionquery.impl; + +import java.util.List; + +/** + * Created by kormushin on 09.10.15. + */ +public class UnionStmt { + private List previousResult; + + public FromStmt from(Iterable list) { + FromStmt newFrom = new FromStmt<>(list); + newFrom.setPreviousResult(previousResult); + return newFrom; + } + + public UnionStmt(List previousResult) { + this.previousResult = previousResult; + } + + +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Column.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Column.java new file mode 100644 index 0000000..3ada203 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Column.java @@ -0,0 +1,13 @@ +package ru.fizteh.fivt.students.chipak.miniorm; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Column { + String name() default ""; +} diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseService.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseService.java new file mode 100644 index 0000000..29cd31d --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseService.java @@ -0,0 +1,281 @@ +package ru.fizteh.fivt.students.chipak.miniorm; + + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +//import org.h2.jdbcx.JdbcConnectionPool; + +public class DatabaseService { + private Class tableClass; + private String tableName; + private Connection dbConnection; + private List columns; + private TypedColumn primaryKeyColumn; + + private static final String STANDARD_DATABASE_PATH = "./chipakdb"; + + private enum DataType { + INTEGER("INT", Boolean.class, Byte.class, Short.class, Integer.class, Long.class), + DOUBLE("DOUBLE", Float.class, Double.class), + TEXT("VARCHAR(255)", String.class); + + private final String nameSQL; + private final Class[] examples; + + DataType(String sqllikeName, Class... variety) { + nameSQL = sqllikeName; + examples = variety; + } + + private static DataType valueOf(Class typeClass) throws DatabaseServiceException { + for (DataType type : values()) { + for (Class testClass : type.examples) { + if (typeClass.equals(testClass)) { + return type; + } + } + } + throw new DatabaseServiceException("This type is not supported" + + typeClass.getSimpleName()); + } + } + + private final class TypedColumn { + private DataType type; + private String name; + private Field field; + + private TypedColumn(Field realField) throws DatabaseServiceException { + field = realField; + field.setAccessible(true); + Column columnAnnotation = field.getAnnotation(Column.class); + if (columnAnnotation == null) { + throw new DatabaseServiceException("annotate the field"); + } + name = columnAnnotation.name(); + if (name.equals("")) { + name = toSnakeCase(field.getName()); + } + type = DataType.valueOf(field.getType()); + } + } + + private static String toSnakeCase(String camelCase) { + StringBuilder nameBuilder = new StringBuilder(); + for (int i = 0; i < camelCase.length(); ++i) { + if (camelCase.charAt(i) >= 'A' && camelCase.charAt(i) <= 'Z') { + if (i > 0 && camelCase.charAt(i - 1) >= 'a' && camelCase.charAt(i - 1) <= 'z') { + nameBuilder.append('_'); + } + nameBuilder.append((char) (camelCase.charAt(i) - 'A' + 'a')); + } else { + nameBuilder.append(camelCase.charAt(i)); + } + } + return nameBuilder.toString(); + } + + private String createColumnsPattern(Function convert) { + StringBuilder values = new StringBuilder(); + for (TypedColumn column : columns) { + values.append(convert.apply(column)) + .append(','); + } + values.deleteCharAt(values.length() - 1); + return values.toString(); + } + + private void initDatabaseTable(Class annotatedTableClass) throws DatabaseServiceException { + tableClass = annotatedTableClass; + Table tableAnnotation = tableClass.getAnnotation(Table.class); + if (tableAnnotation == null) { + throw new DatabaseServiceException("annotate the table class"); + } + tableName = tableAnnotation.name(); + if (tableName.equals("")) { + tableName = toSnakeCase(tableClass.getSimpleName()); + } + Field[] allFields = tableClass.getDeclaredFields(); + columns = new ArrayList<>(); + for (Field field : allFields) { + if (field.isAnnotationPresent(Column.class)) { + columns.add(new TypedColumn(field)); + if (field.isAnnotationPresent(PrimaryKey.class)) { + if (primaryKeyColumn != null) { + throw new DatabaseServiceException("please enter one prim key"); + } + primaryKeyColumn = columns.get(columns.size() - 1); + } + } + } + } + + private void initConnection(String databasePath) throws DatabaseServiceException { + try { + dbConnection = DriverManager.getConnection("jdbc:h2:" + databasePath, "sa", ""); + } catch (SQLException e) { + throw new DatabaseServiceException("Connection not found: " + e.getMessage(), e); + } + } + + public DatabaseService(Class annotatedTableClass) throws DatabaseServiceException { + initDatabaseTable(annotatedTableClass); + initConnection(STANDARD_DATABASE_PATH); + } + + public final void createTable() throws DatabaseServiceException { + StringBuilder columnsString = new StringBuilder(); + for (TypedColumn column : columns) { + columnsString.append(column.name) + .append(' ') + .append(column.type.nameSQL); + if (column.field.isAnnotationPresent(PrimaryKey.class)) { + columnsString.append(" PRIMARY KEY CAN'T BE NULL"); + } + columnsString.append(','); + } + columnsString.deleteCharAt(columnsString.length() - 1); + try { + dbConnection.createStatement().execute("CREATE TABLE " + tableName + + "(" + columnsString.toString() + ")"); + } catch (SQLException e) { + throw new DatabaseServiceException("can't create: " + e.getMessage(), e); + } + } + + + public final void dropTable() throws DatabaseServiceException { + try { + dbConnection.createStatement().execute("DROP TABLE " + tableName); + } catch (SQLException e) { + throw new DatabaseServiceException("can't drop table: " + e.getMessage(), e); + } + } + + + public final void insert(T row) throws DatabaseServiceException { + try { + PreparedStatement statement = dbConnection.prepareStatement("INSERT INTO " + tableName + + " VALUES (" + createColumnsPattern(c -> "?") + ")"); + for (int i = 0; i < columns.size(); ++i) { + statement.setString(i + 1, String.valueOf(columns.get(i).field.get(row))); + } + statement.execute(); + } catch (SQLException | IllegalArgumentException | IllegalAccessException e) { + throw new DatabaseServiceException("can't insert: " + e.getMessage()); + } + } + + + public final void update(T row) throws DatabaseServiceException { + if (primaryKeyColumn == null) { + throw new DatabaseServiceException("no prim key"); + } + try { + PreparedStatement statement = dbConnection.prepareStatement("UPDATE " + tableName + + " SET " + createColumnsPattern(c -> c.name + "=?") + " WHERE " + primaryKeyColumn.name + "=?"); + for (int i = 0; i < columns.size(); ++i) { + statement.setString(i + 1, String.valueOf(columns.get(i).field.get(row))); + } + statement.setString(columns.size() + 1, primaryKeyColumn.field.get(row).toString()); + statement.execute(); + } catch (SQLException | IllegalArgumentException | IllegalAccessException e) { + throw new DatabaseServiceException("Can't update: " + e.getMessage()); + } + } + + + public final void deleteByKey(K key) throws DatabaseServiceException { + if (primaryKeyColumn == null) { + throw new DatabaseServiceException("no prim key"); + } + try { + PreparedStatement statement = dbConnection.prepareStatement("DELETE FROM " + tableName + + " WHERE " + primaryKeyColumn.name + "=?"); + statement.setString(1, key.toString()); + statement.execute(); + } catch (SQLException | IllegalArgumentException e) { + throw new DatabaseServiceException("Can't delete" + e.getMessage()); + } + } + + + public final void delete(T row) throws DatabaseServiceException { + try { + deleteByKey(primaryKeyColumn.field.get(row).toString()); + } catch (IllegalAccessException e) { + throw new DatabaseServiceException("Can't delete: " + e.getMessage()); + } + } + + private List getRealClasses(ResultSet result) throws IllegalArgumentException, IllegalAccessException, + SQLException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException { + List output = new ArrayList<>(); + while (result.next()) { + T row = tableClass.newInstance(); + for (int i = 0; i < columns.size(); ++i) { + String value = result.getString(i + 1); + if (columns.get(i).field.getType().equals(String.class)) { + columns.get(i).field.set(row, value); + } else { + columns.get(i).field.set(row, columns.get(i).field.getType().getMethod("valueOf", String.class) + .invoke(null, value)); + } + } + output.add(row); + } + result.close(); + return output; + } + + public final T queryById(K key) throws DatabaseServiceException { + if (primaryKeyColumn == null) { + throw new DatabaseServiceException("need prim key"); + } + if (!primaryKeyColumn.field.getType().isInstance(key)) { + throw new DatabaseServiceException("key type is not type of primary key"); + } + + try { + PreparedStatement statement = dbConnection.prepareStatement("SELECT " + createColumnsPattern(c -> c.name) + + " FROM " + tableName + " WHERE " + primaryKeyColumn.name + "=?"); + statement.setString(1, key.toString()); + List result = getRealClasses(statement.executeQuery()); + if (result.isEmpty()) { + return null; + } + return result.get(0); + } catch (SQLException | IllegalArgumentException | IllegalAccessException | InstantiationException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new DatabaseServiceException("Can't get the instantiate the row: " + e.getMessage(), e); + } + } + + + public final List queryForAll() throws DatabaseServiceException { + try { + return getRealClasses(dbConnection.prepareStatement("SELECT " + createColumnsPattern(c -> c.name) + + " FROM " + tableName).executeQuery()); + } catch (SQLException | IllegalArgumentException | IllegalAccessException + | InstantiationException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new DatabaseServiceException("Can't get or instantiate the row: " + e.getMessage(), e); + } + } + + @Override + protected final void finalize() { + try { + dbConnection.close(); + } catch (SQLException e) { + System.err.println("can not close connection: " + e.getMessage()); + } + } +} diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseServiceException.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseServiceException.java new file mode 100644 index 0000000..d3cef49 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/DatabaseServiceException.java @@ -0,0 +1,12 @@ +package ru.fizteh.fivt.students.chipak.miniorm; + +public class DatabaseServiceException extends Exception { + + public DatabaseServiceException(String message) { + super(message); + } + + public DatabaseServiceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/PrimaryKey.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/PrimaryKey.java new file mode 100644 index 0000000..571873a --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/PrimaryKey.java @@ -0,0 +1,11 @@ +package ru.fizteh.fivt.students.chipak.miniorm; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface PrimaryKey { +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Table.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Table.java new file mode 100644 index 0000000..591c659 --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/miniorm/Table.java @@ -0,0 +1,12 @@ +package ru.fizteh.fivt.students.chipak.miniorm; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Table { + String name() default ""; +} \ No newline at end of file diff --git a/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/reverser/Reverser.java b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/reverser/Reverser.java new file mode 100644 index 0000000..f6d07dc --- /dev/null +++ b/solutions/chipak/src/main/java/ru/fizteh/fivt/students/chipak/reverser/Reverser.java @@ -0,0 +1,20 @@ +package ru.fizteh.fivt.students.chipak.reverser; + + +import java.util.Arrays; +import java.util.Collections; + +public class Reverser { + public static void main(String[] args) { + for (int i = args.length - 1; i >= 0; i--) { + + String[] sIn = args[i].split("[\\s+\\\\\"]"); + + Collections.reverse(Arrays.asList(sIn)); + + for (int j = 0; j < sIn.length; j++) { + System.out.print(sIn[j] + " "); + } + } + } +} \ No newline at end of file