From 6e367b8e30de2ddc1e9e5fcfc4a2c965a3e14e1e Mon Sep 17 00:00:00 2001 From: liza22 Date: Wed, 16 Dec 2015 21:13:18 +0300 Subject: [PATCH 01/17] TwitterStream --- projects/liza22/pom.xml | 26 +++++ .../main/java/ru/mipt/diht/students/App.java | 13 +++ .../ru/mipt/diht/students/liza22/.gitignore | 1 + .../students/liza22/TwitterStream/pom.xml | 75 +++++++++++++ .../src/main/java/TwitterStream.java | 73 ++++++++++++ .../src/main/java/config/Arguments.java | 106 ++++++++++++++++++ .../src/main/java/config/Constants.java | 31 +++++ .../src/main/java/config/TwitterConfig.java | 98 ++++++++++++++++ .../main/java/core/handling/TweetHandler.java | 15 +++ .../core/handling/TweetHandlerFactory.java | 26 +++++ .../impl/PrintResultOfQueryTweetsHandler.java | 101 +++++++++++++++++ .../impl/PrintStreamOfTweetsHandler.java | 99 ++++++++++++++++ .../java/core/providing/TweetsProvider.java | 14 +++ .../core/providing/TweetsProviderFactory.java | 29 +++++ .../providing/impl/TweetsByQueryProvider.java | 65 +++++++++++ .../providing/impl/TweetsStreamProvider.java | 96 ++++++++++++++++ .../java/core/quering/FilterQueryBuilder.java | 55 +++++++++ .../java/core/quering/SearchQueryBuilder.java | 94 ++++++++++++++++ .../src/main/java/model/Mode.java | 8 ++ .../src/main/java/model/Tweet.java | 80 +++++++++++++ .../src/main/java/model/TwitterUser.java | 41 +++++++ .../src/main/java/utils/GeoUtils.java | 49 ++++++++ .../src/main/java/utils/TextUtils.java | 16 +++ .../TwitterStream/src/main/resources/help.txt | 11 ++ .../java/ru/mipt/diht/students/AppTest.java | 38 +++++++ projects/pom.xml | 9 +- 26 files changed, 1265 insertions(+), 4 deletions(-) create mode 100644 projects/liza22/pom.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/App.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt create mode 100644 projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml new file mode 100644 index 0000000..02e4233 --- /dev/null +++ b/projects/liza22/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + ru.mipt.diht.students + parent + 1.0-SNAPSHOT + + ru.mipt.diht.students + liza22 + 1.0-SNAPSHOT + liza22 + http://maven.apache.org + + UTF-8 + + + + junit + junit + 3.8.1 + test + + + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/App.java b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java new file mode 100644 index 0000000..38fae44 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java @@ -0,0 +1,13 @@ +package ru.mipt.diht.students; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore new file mode 100644 index 0000000..031401d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore @@ -0,0 +1 @@ +twitter.cfg \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml new file mode 100644 index 0000000..d3f7776 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + com.twitter.stream + twitterstream + 1.0 + + + 1.7 + 1.7 + + 1.48 + 4.0.4 + + + + + com.beust + jcommander + ${jcommander-version} + + + org.twitter4j + twitter4j-core + ${twitter4j-version} + + + org.twitter4j + twitter4j-stream + ${twitter4j-version} + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + TwitterStream + lib/*d + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.5.1 + + + copy-dependencies + package + + copy-dependencies + + + runtime + ${project.build.directory}/lib/ + + + + + + + + + \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java new file mode 100644 index 0000000..76f5418 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -0,0 +1,73 @@ +import com.beust.jcommander.JCommander; +import config.Arguments; +import config.Constants; +import config.TwitterConfig; +import core.handling.TweetHandler; +import core.handling.TweetHandlerFactory; +import core.providing.TweetsProvider; +import core.providing.TweetsProviderFactory; +import model.Mode; + +import java.io.*; + +/** + * Main Class. + */ +public class TwitterStream { + + public static void main(String[] argsString) { + extractArguments(argsString); + Arguments arguments = Arguments.getInstance(); + + // In case of HELP page is requested, just print HELP file content and exit application + if (arguments.isHelpRequest()) { + printHelp(System.out); + System.exit(0); + } + try { + // read and initialize twitter configuration + TwitterConfig twitterConfig = new TwitterConfig(); + // define working mode of application + Mode workingMode = (arguments.isStreamMode()) ? Mode.STREAM : Mode.QUERY; + // get tweets provider for selected working mode and initialize this one + TweetsProvider tweetsProvider = TweetsProviderFactory.getProvider(workingMode); + tweetsProvider.init(twitterConfig); + // get tweet handler for selected working mode + TweetHandler tweetHandler = TweetHandlerFactory.getHandler(workingMode); + // start tweets providing and handling + tweetsProvider.provide(tweetHandler); + } catch (Exception e) { + System.err.println("Application TwitterStream has been occasionally crashed " + + "with error = \"" + e.getMessage() + "\""); + System.err.println("Application will be terminated with error code."); + System.exit(1); + } + } + + /** + * Transforms arguments string to Arguments object with parsed fields. + * @param argsString arguments strings from the input + */ + private static void extractArguments(String[] argsString) { + JCommander jCommander = new JCommander(); + jCommander.addObject(Arguments.getInstance()); + jCommander.parse(argsString); + } + + /** + * Prints the content of HELP file to the passed output stream. + * @param out stream where HELP page will be printed + */ + private static void printHelp(OutputStream out) { + try { + byte[] buffer = new byte[1024]; + try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { + for (int length; (length = input.read(buffer)) != -1; ) { + out.write(buffer, 0, length); + } + } + } catch (IOException e) { + System.err.println("Problem with reading help file: \"" + e.getMessage() + "\""); + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java new file mode 100644 index 0000000..0a78225 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java @@ -0,0 +1,106 @@ +package config; + +import com.beust.jcommander.Parameter; + +import java.util.List; + +/** + * Arguments storage. + * Used JCommander library. + * + * @see http://jcommander.org/ + */ +public class Arguments { + private static final Arguments INSTANCE = new Arguments(); + + private Arguments() {} + + public static Arguments getInstance() { + return INSTANCE; + } + + @Parameter(names = {"--query", "-q"}, + required = true, + description = "Query or keywords for stream") + private List keywords; + + @Parameter(names = {"--place", "-p"}, + required = true, + description = "Location for search tweets") + private String place; + + @Parameter(names = {"--stream", "-s"}, + description = "Stream mode when tweets printed with delay") + private boolean streamMode; + + @Parameter(names = "--hideRetweets", + description = "Hides retweets at all") + private boolean hideRetweets; + + @Parameter(names = {"--limit", "-l"}, + description = "Limits the number of printed tweets") + private Integer limitOfTweets = Constants.NO_TWEETS_LIMIT; + + @Parameter(names = {"--help", "-h"}, + help = true, + description = "Requests the help page") + private boolean helpRequest; + + @Parameter(names = {"--verbose", "-v"}, + description = "Verbose mode to print more information") + private boolean verbose; + + /** + * Array of keywords in case of tweets stream requested. + * @return array of keywords to be tracked + */ + public String[] getKeywords() { + String[] keywordsArray = new String[keywords.size()]; + return keywords.toArray(keywordsArray); + } + + /** + * Suppose that query for Search tweets is element with 0 index. + * @return search tweets query + */ + public String getQuery() { + return keywords.get(0); + } + + public String getPlace() { + return place; + } + + public boolean isStreamMode() { + return streamMode; + } + + public boolean hideRetweets() { + return hideRetweets; + } + + public Integer getLimitOfTweets() { + return limitOfTweets; + } + + public boolean isHelpRequest() { + return helpRequest; + } + + public boolean isVerboseMode() { + return verbose; + } + + @Override + public String toString() { + return "Arguments{" + + "keywords=" + keywords + + ", place='" + place + '\'' + + ", streamMode=" + streamMode + + ", hideRetweets=" + hideRetweets + + ", limitOfTweets=" + limitOfTweets + + ", helpRequest=" + helpRequest + + ", verboseMode=" + verbose + + '}'; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java new file mode 100644 index 0000000..b9945af --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java @@ -0,0 +1,31 @@ +package config; + +/** + * Application constants storage. + */ +public final class Constants { + /** + * Reconnect timeout to twitter in seconds . + */ + public static final int RECONNECT_TIMEOUT_SECS = 10; + /** + * Default value of limit argument. + */ + public static final int NO_TWEETS_LIMIT = -1; + /** + * Delay between two printing of tweets. + */ + public static final int PRINT_TWEET_DELAY_SECS = 1; + /** + * Message which is printed in verbose mode when no any tweet to print for stream. + */ + public static final String NO_TWEET_MESSAGE = "..."; + /** + * Name of resource - twitter config file. + */ + public static final String TWITTER_CONFIG_FILE = "twitter.cfg"; + /** + * Name of resource - help content file. + */ + public static final String HELP_FILE = "help.txt"; +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java new file mode 100644 index 0000000..a34a176 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java @@ -0,0 +1,98 @@ +package config; + +import twitter4j.auth.AccessToken; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationBuilder; + +import java.io.*; + +/** + * Class loads and holds Twitter Access configuration from file resource + * and provides methods to get {@link twitter4j.conf.Configuration} and {@link twitter4j.auth.AccessToken} + */ +public class TwitterConfig { + private static final String CONSUMER_KEY_PROP_NAME = "consumerKey"; + private static final String CONSUMER_SECRET_PROP_NAME = "consumerSecret"; + private static final String ACCESS_TOKEN_PROP_NAME = "accessToken"; + private static final String ACCESS_TOKEN_SECRET_PROP_NAME = "accessTokenSecret"; + + private String consumerKey; + private String consumerSecret; + private String accessToken; + private String accessTokenSecret; + + public TwitterConfig() { + init(); + } + + private void init() { + File cfgFile = new File(Constants.TWITTER_CONFIG_FILE); + try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)))) + { + while (in.ready()) { + String line = in.readLine(); + int indexOfDelimiter = line.indexOf('='); + if (indexOfDelimiter == -1) { + System.err.println("Incorrect line in twitter configuration = '" + line + "'"); + continue; + } + String propName = line.substring(0, indexOfDelimiter); + String propValue = line.substring(indexOfDelimiter+1, line.length()); + switch (propName) { + case CONSUMER_KEY_PROP_NAME: + consumerKey = propValue; + break; + case CONSUMER_SECRET_PROP_NAME: + consumerSecret = propValue; + break; + case ACCESS_TOKEN_PROP_NAME: + accessToken = propValue; + break; + case ACCESS_TOKEN_SECRET_PROP_NAME: + accessTokenSecret = propValue; + break; + default: + System.err.println("Property '" + propName + "' not recognized"); + } + } + } catch (FileNotFoundException e) { + System.err.println("Twitter config file by path = \"" + cfgFile.getAbsolutePath() + "\" not found"); + } catch (IOException e) { + System.err.println("Problem with reading twitter config file: " + e.getMessage()); + } + + validate(); + } + + private void validate() { + if (consumerKey == null || + consumerSecret == null || + accessToken == null || + accessTokenSecret == null) { + throw new IllegalStateException("Twitter configuration file is incorrect"); + } + } + + public AccessToken getAccessToken() { + return new AccessToken(accessToken, accessTokenSecret); + } + + public Configuration getConfiguration() { + ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(). + setOAuthConsumerKey(consumerKey). + setOAuthConsumerSecret(consumerSecret). + setOAuthAccessToken(accessToken). + setOAuthAccessTokenSecret(accessTokenSecret); + return configurationBuilder.build(); + } + + @Override + public String toString() { + return "TwitterConfig{" + + "consumerKey='" + consumerKey + '\'' + + ", consumerSecret='" + consumerSecret + '\'' + + ", accessToken='" + accessToken + '\'' + + ", accessTokenSecret='" + accessTokenSecret + '\'' + + '}'; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java new file mode 100644 index 0000000..01d81fc --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java @@ -0,0 +1,15 @@ +package core.handling; + +import model.Tweet; + +/** + * Tweet handler interface. + */ +public interface TweetHandler { + + /** + * Handles tweet by any way. + * @param tweet obtained tweet + */ + void handle(Tweet tweet); +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java new file mode 100644 index 0000000..65cb51a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java @@ -0,0 +1,26 @@ +package core.handling; + +import core.handling.impl.PrintResultOfQueryTweetsHandler; +import core.handling.impl.PrintStreamOfTweetsHandler; +import model.Mode; + +public class TweetHandlerFactory { + + private TweetHandlerFactory() {} + + /** + * Gets tweets handler depending on the working mode. + * @param mode working mode of application + * @return tweet handler implementation + */ + public static TweetHandler getHandler(Mode mode) { + switch (mode) { + case STREAM: + return new PrintStreamOfTweetsHandler(System.out); + case QUERY: + return new PrintResultOfQueryTweetsHandler(System.out); + default: + throw new IllegalArgumentException("Mode = " + mode + " is not supported"); + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java new file mode 100644 index 0000000..6854901 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java @@ -0,0 +1,101 @@ +package core.handling.impl; + +import core.handling.TweetHandler; +import model.Tweet; +import utils.TextUtils; + +import java.io.PrintStream; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * This handler is used in QUERY mode of application. + * It prints tweets every time when new tweet is come. + * + * When new tweet is obtained (method 'handle' invoked) this handler prints + * formatted representation of this new tweet. + */ +public class PrintResultOfQueryTweetsHandler implements TweetHandler { + private PrintStream out; + + private AtomicLong tweetCounter = new AtomicLong(0); + + public PrintResultOfQueryTweetsHandler(PrintStream out) { + this.out = out; + } + + @Override + public void handle(Tweet tweet) { + out.println("Tweet#" + tweetCounter.incrementAndGet() + ":"); + out.println(formatTweet(tweet)); + } + + /** + * Print format is the following: + * + * If tweet IS NOT retweeted + * ---------------------------------------------------------------------------------------- + * [] @: + * ---------------------------------------------------------------------------------------- + * + * If tweet IS retweeted + * ---------------------------------------------------------------------------------------- + * [] @: ретвитнул @: ( ретвитов) + * ---------------------------------------------------------------------------------------- + * + * @param tweet tweet object to be printed + * @return text representation of tweet according to format + */ + private static String formatTweet(Tweet tweet) { + StringBuilder tweetView = new StringBuilder(256); + tweetView.append("----------------------------------------------------------------------------------------\n"); + if (tweet.isNotRetweet()) { + tweetView.append("[").append(formatTime(tweet.getTime())).append("] "). + append("@").append(getNickname(tweet)). + append(": ").append(tweet.getText()); + } else { + Tweet retweetedTweet = tweet.getRetweetedTweet(); + tweetView.append("[").append(formatTime(tweet.getTime())).append("] "). + append("@").append(getNickname(tweet)). + append(": ретвитнул @").append(getNickname(retweetedTweet)). + append(": ").append(retweetedTweet.getText()). + append(" (").append(retweetedTweet.getRetweetCount()).append(" ретвитов)"); + } + tweetView.append("\n----------------------------------------------------------------------------------------"); + return tweetView.toString(); + } + + private static String getNickname(Tweet tweet) { + String nick = tweet.getAuthor().getName(); + return TextUtils.coloredText(nick, TextUtils.COLOR_BLUE); + } + + /** + * Time format is the following: + * Время должно быть в формате: + * "Только что" - если менее 2х минут назад + * "n минут назад" - если менее часа назад (n - цифрами) + * "n часов назад" - если более часа, но сегодня (n - цифрами) + * "вчера" - если вчера + * "n дней назад" - в остальных случаях (n - цифрами) + * + * @param then the tweet's time in milliseconds + * @return text representation of the tweet's time according to format + */ + private static String formatTime(long then) { + long now = new Date().getTime(); + long diffInMinutes = (now - then) / 1_000 / 60; // milliseconds/1_000/60 = minutes + if (diffInMinutes < 2) { + return "Только что"; + } else if (TimeUnit.MINUTES.toHours(diffInMinutes) < 1) { + return diffInMinutes + " минут назад"; + } else if (TimeUnit.MINUTES.toHours(diffInMinutes) >= 1 && TimeUnit.MINUTES.toDays(diffInMinutes) < 1) { + return TimeUnit.MINUTES.toHours(diffInMinutes) + " часов назад"; + } else if (TimeUnit.MINUTES.toDays(diffInMinutes) >= 1 && TimeUnit.MINUTES.toDays(diffInMinutes) < 2) { + return "вчера"; + } else { + return TimeUnit.MINUTES.toDays(diffInMinutes) + " дней назад"; + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java new file mode 100644 index 0000000..38b07fa --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java @@ -0,0 +1,99 @@ +package core.handling.impl; + +import config.Arguments; +import config.Constants; +import core.handling.TweetHandler; +import model.Tweet; +import utils.TextUtils; + +import java.io.PrintStream; +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicLong; + +/** + * This handler is used in STREAM mode of application. + * It prints tweets every Constants.PRINT_TWEET_DELAY_SECS (by default every 1 second). + * + * When new tweet is obtained (method 'handle' invoked) this handler stores this tweet + * to internal queue. When next print step is come, handler takes tweet from queue + * (by 'poll' method) and prints this tweet. + * In case when no available tweet in queue, it will print nothing or + * Constants.NO_TWEET_MESSAGE in VERBOSE mode. + */ +public class PrintStreamOfTweetsHandler implements TweetHandler { + private PrintStream out; + private Queue tweetQueue; + + private boolean started = false; + private AtomicLong tweetCounter = new AtomicLong(0); + + public PrintStreamOfTweetsHandler(final PrintStream out) { + this.out = out; + tweetQueue = new ArrayDeque<>(); + } + + @Override + public void handle(Tweet tweet) { + tweetQueue.offer(tweet); + + if (!started) { + // schedule timer with task of printing tweets from queue + new Timer().schedule(new TimerTask() { + @Override + public void run() { + Tweet next = tweetQueue.poll(); + if (next != null) { + out.println("Tweet#" + tweetCounter.incrementAndGet() + ":"); + out.println(formatTweet(next)); + } else { + if (Arguments.getInstance().isVerboseMode()) { + out.println(Constants.NO_TWEET_MESSAGE); + } + } + } + }, 0, Constants.PRINT_TWEET_DELAY_SECS * 1_000); + started = true; + } + } + + /** + * Print format is the following: + * + * If tweet IS NOT retweeted + * ---------------------------------------------------------------------------------------- + * @: + * ---------------------------------------------------------------------------------------- + * + * If tweet IS retweeted + * ---------------------------------------------------------------------------------------- + * @: ретвитнул @: ( ретвитов) + * ---------------------------------------------------------------------------------------- + * + * @param tweet tweet object to be printed + * @return text representation of tweet according to format + */ + private static String formatTweet(Tweet tweet) { + StringBuilder tweetView = new StringBuilder(256); + tweetView.append("----------------------------------------------------------------------------------------\n"); + if (tweet.isNotRetweet()) { + tweetView.append("@").append(getNickname(tweet)). + append(": ").append(tweet.getText()); + } else { + Tweet retweetedTweet = tweet.getRetweetedTweet(); + tweetView.append("@").append(getNickname(tweet)). + append(": ретвитнул @").append(getNickname(retweetedTweet)). + append(": ").append(retweetedTweet.getText()). + append(" (").append(retweetedTweet.getRetweetCount()).append(" ретвитов)"); + } + tweetView.append("\n----------------------------------------------------------------------------------------"); + return tweetView.toString(); + } + + private static String getNickname(Tweet tweet) { + String nick = tweet.getAuthor().getName(); + return TextUtils.coloredText(nick, TextUtils.COLOR_BLUE); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java new file mode 100644 index 0000000..e56766a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java @@ -0,0 +1,14 @@ +package core.providing; + +import config.TwitterConfig; +import core.handling.TweetHandler; + +/** + * Tweets provider interface. + */ +public interface TweetsProvider { + + void init(TwitterConfig twitterConfig); + + void provide(TweetHandler handler); +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java new file mode 100644 index 0000000..c77911d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java @@ -0,0 +1,29 @@ +package core.providing; + +import core.providing.impl.TweetsByQueryProvider; +import core.providing.impl.TweetsStreamProvider; +import model.Mode; + +/** + * Tweets provider factory. + */ +public class TweetsProviderFactory { + + private TweetsProviderFactory() {} + + /** + * Gets tweets provider depending on the working mode. + * @param mode working mode of application + * @return tweets provider implementation + */ + public static TweetsProvider getProvider(Mode mode) { + switch (mode) { + case STREAM: + return new TweetsStreamProvider(); + case QUERY: + return new TweetsByQueryProvider(); + default: + throw new IllegalArgumentException("Mode = " + mode + " is not supported"); + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java new file mode 100644 index 0000000..0de15dc --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java @@ -0,0 +1,65 @@ +package core.providing.impl; + +import config.Arguments; +import config.Constants; +import config.TwitterConfig; +import core.handling.TweetHandler; +import core.providing.TweetsProvider; +import core.quering.SearchQueryBuilder; +import model.Tweet; +import twitter4j.*; + +import java.util.concurrent.TimeUnit; + +/** + * Tweets by query provider, provides requested tweets to handler. + * + * Query is built by SearchQueryBuilder and method 'search' of + * Twitter instance is invoked. + * + * QueryResult contains list of statuses, which transformed to + * internal Tweet objects, after that these tweets are sent to + * handler. + */ +public class TweetsByQueryProvider implements TweetsProvider { + private Twitter twitter; + private Query query; + + @Override + public void init(TwitterConfig twitterConfig) { + twitter = new TwitterFactory(twitterConfig.getConfiguration()).getInstance(); + query = new SearchQueryBuilder(twitter).buildQuery(); + } + + @Override + public void provide(TweetHandler handler) { + try { + QueryResult result = twitter.search(query); + if (result.getTweets() == null || result.getTweets().isEmpty()) { + System.out.println("No any tweets by specified query and place found"); + } + for (Status status : result.getTweets()) { + // transform status to Tweet object and send to handler + Tweet tweet = Tweet.valueOf(status); + if (Arguments.getInstance().hideRetweets() && tweet.isRetweet()) { + // skip this tweet + continue; + } + handler.handle(tweet); + } + } catch (TwitterException e) { + System.err.println("Twitter has been occasionally crashed with error: \"" + e.getMessage() + "\""); + System.err.println("Try one more time... [timeout = " + Constants.RECONNECT_TIMEOUT_SECS + " secs]"); + timeout(Constants.RECONNECT_TIMEOUT_SECS); + provide(handler); + } + } + + private static void timeout(int seconds) { + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + // do nothing + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java new file mode 100644 index 0000000..e55b933 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java @@ -0,0 +1,96 @@ +package core.providing.impl; + +import config.Arguments; +import config.Constants; +import config.TwitterConfig; +import core.handling.TweetHandler; +import core.providing.TweetsProvider; +import core.quering.FilterQueryBuilder; +import model.Tweet; +import twitter4j.*; +import twitter4j.auth.AccessToken; +import twitter4j.conf.Configuration; + +import java.util.concurrent.TimeUnit; + +/** + * Tweets stream provider, provides tweets to TweetHandler. + * + * This class implements StatusAdapter and registers itself + * as StatusListener in TwitterStream. + * Every time when new status obtained the transformation to + * internal Tweet object performed, after that this Tweet sent + * to the handler. + */ +public class TweetsStreamProvider extends StatusAdapter implements TweetsProvider { + private Configuration configuration; + private AccessToken accessToken; + + private TwitterStream twitterStream; + private FilterQuery filterQuery; + + private TweetHandler tweetHandler; + + @Override + public void init(TwitterConfig twitterConfig) { + configuration = twitterConfig.getConfiguration(); + accessToken = twitterConfig.getAccessToken(); + } + + @Override + public void provide(TweetHandler handler) { + this.tweetHandler = handler; + connect(); + } + + @Override + public void onStatus(Status status) { + Tweet tweet = Tweet.valueOf(status); + if (Arguments.getInstance().hideRetweets() && tweet.isRetweet()) { + // skip this tweet + return; + } + tweetHandler.handle(tweet); + } + + @Override + public void onException(Exception e) { + System.err.println("Twitter stream has been occasionally crashed with error: \"" + e.getMessage() + "\""); + System.err.println("Try to reconnect... [timeout = " + Constants.RECONNECT_TIMEOUT_SECS + " secs]"); + reconnect(); + } + + private void connect() { + twitterStream = new TwitterStreamFactory(configuration).getInstance(accessToken); + Twitter twitter = new TwitterFactory(configuration).getInstance(); + filterQuery = new FilterQueryBuilder(twitter).buildQuery(); + // register itself as status listener + // method 'onStatus' will execute every time when new tweet obtained + twitterStream.addListener(this); + twitterStream.filter(filterQuery); + } + + private void disconnect() { + if (twitterStream != null) { + twitterStream.cleanUp(); + twitterStream.shutdown(); + // help GC + twitterStream = null; + } + } + + private void reconnect() { + // reconnect is performed with timeout between disconnect and new connect + disconnect(); + timeout(Constants.RECONNECT_TIMEOUT_SECS); + connect(); + } + + private static void timeout(int seconds) { + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + // do nothing + } + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java new file mode 100644 index 0000000..6f3f890 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java @@ -0,0 +1,55 @@ +package core.quering; + +import config.Arguments; +import utils.GeoUtils; +import twitter4j.*; + +/** + * FilterQuery builder to build query for Twitter searching + * based on arguments (query, place). + */ +public class FilterQueryBuilder { + private Twitter twitter; + + public FilterQueryBuilder(Twitter twitter) { + this.twitter = twitter; + } + + public FilterQuery buildQuery() { + Arguments arguments = Arguments.getInstance(); + + FilterQuery query = new FilterQuery(); + query.track(arguments.getKeywords()); + + // calculate and set place for tweets + try { + Place place = GeoUtils.findPlaceByName(twitter, arguments.getPlace()); + GeoLocation[] vertices = place.getBoundingBoxCoordinates()[0]; + /* + * We try to find two points of box + * - the first with MIN latitude and longitude + * - the second with MAX latitude and longitude + * These two points will be used as filtering location for tweets. + * + * For additional details see: + * https://dev.twitter.com/streaming/overview/request-parameters#locations + * Checked with "New York City" ({-74,40},{-73,41}) + */ + double minLongitude = Double.MAX_VALUE, minLatitude = Double.MAX_VALUE; + double maxLongitude = -Double.MAX_VALUE, maxLatitude = -Double.MAX_VALUE; + for (GeoLocation vertex : vertices) { + minLongitude = Math.min(minLongitude, vertex.getLongitude()); + minLatitude = Math.min(minLatitude, vertex.getLatitude()); + maxLongitude = Math.max(maxLongitude, vertex.getLongitude()); + maxLatitude = Math.max(maxLatitude, vertex.getLatitude()); + } + double[][] locations = {{minLongitude, minLatitude}, {maxLongitude, maxLatitude}}; + query.locations(locations); + } catch (TwitterException te) { + System.err.println("Searching of places has been crashed with error = \"" + te.getMessage() + "\""); + System.err.println("Search query will be created without place condition."); + } + + return query; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java new file mode 100644 index 0000000..70cd998 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java @@ -0,0 +1,94 @@ +package core.quering; + +import config.Arguments; +import config.Constants; +import utils.GeoUtils; +import twitter4j.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * SearchQuery builder to build query for tweets streaming + * based on arguments (keywords, place). + */ +public class SearchQueryBuilder { + private Twitter twitter; + + public SearchQueryBuilder(Twitter twitter) { + this.twitter = twitter; + } + + public Query buildQuery() { + Arguments arguments = Arguments.getInstance(); + Query query = new Query(); + // set query for tweets + query.setQuery(arguments.getQuery()); + // set limit of tweets if specified in arguments + if (arguments.getLimitOfTweets() != Constants.NO_TWEETS_LIMIT) { + query.setCount(arguments.getLimitOfTweets()); + } + // calculate and set place for tweets + try { + Place place = GeoUtils.findPlaceByName(twitter, arguments.getPlace()); + GeoLocation[] vertices = place.getBoundingBoxCoordinates()[0]; + /* + * Implemented approach which described in the task: + * + * Для Twitter.search использовать среднее арифметическое широты и долготы + * Place.getBoundingBoxCoordinates() и радиус как половину максимального + * расстояния между точками. + */ + GeoLocation center = getCenter(vertices); + double radius = getRadius(vertices); + query.setGeoCode(center, radius, Query.Unit.mi); + } catch (TwitterException te) { + System.err.println("Searching of places has been crashed with error = \"" + te.getMessage() + "\""); + System.err.println("Search query will be created without place condition."); + } + + return query; + } + + public static GeoLocation getCenter(GeoLocation[] vertices) { + double centerLatitude, centerLongitude; + double[] latitudes = new double[vertices.length]; + double[] longitudes = new double[vertices.length]; + for (int i = 0; i < vertices.length; i++) { + GeoLocation vertex = vertices[i]; + latitudes[i] = vertex.getLatitude(); + longitudes[i] = vertex.getLongitude(); + } + centerLatitude = getArithmeticMean(latitudes); + centerLongitude = getArithmeticMean(longitudes); + return new GeoLocation(centerLatitude, centerLongitude); + } + + public static double getRadius(GeoLocation[] vertices) { + List distances = new ArrayList<>(); + // calculate distances between all vertices + for (int i = 0; i < vertices.length-1; i++) { + for (int j = i+1; j < vertices.length; j++) { + GeoLocation vertex1 = vertices[i]; + GeoLocation vertex2 = vertices[j]; + distances.add(GeoUtils.distanceBetweenTwoCoordinates( + vertex1.getLatitude(), vertex1.getLongitude(), + vertex2.getLatitude(), vertex2.getLongitude()) + ); + } + } + // sort list in reverse order (from MAX to MIN) + // and get the first - MAX of all distances + Collections.sort(distances, Collections.reverseOrder()); + return distances.get(0); + } + + public static double getArithmeticMean(double[] numbers){ + double sum = 0; + for (double num : numbers) { + sum += num; + } + return sum / numbers.length; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java new file mode 100644 index 0000000..23dc708 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java @@ -0,0 +1,8 @@ +package model; + +/** + * Working mode of application - as tweets stream or tweets by query. + */ +public enum Mode { + STREAM, QUERY; +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java new file mode 100644 index 0000000..972578f --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java @@ -0,0 +1,80 @@ +package model; + +import twitter4j.Status; + +/** + * Class represents Tweet object. + */ +public class Tweet { + private String text; + private TwitterUser author; + private long time; + private long retweetCount; + private Tweet retweetedTweet; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public TwitterUser getAuthor() { + return author; + } + + public void setAuthor(TwitterUser author) { + this.author = author; + } + + public long getRetweetCount() { + return retweetCount; + } + + public void setRetweetCount(long retweetCount) { + this.retweetCount = retweetCount; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public Tweet getRetweetedTweet() { + return retweetedTweet; + } + + public void setRetweetedTweet(Tweet retweetedTweet) { + this.retweetedTweet = retweetedTweet; + } + + public boolean isRetweet() { + return null != retweetedTweet; + } + + public boolean isNotRetweet() { + return !isRetweet(); + } + + /** + * Factory method to convert twitter4j.Status object to internal model - Tweet object. + * @param twitter4jStatus twitter4j.Status object + * @return Tweet object + */ + public static Tweet valueOf(Status twitter4jStatus) { + Tweet tweet = new Tweet(); + if (twitter4jStatus.getRetweetedStatus() != null) { + tweet.setRetweetedTweet(valueOf(twitter4jStatus.getRetweetedStatus())); + } + tweet.setAuthor(TwitterUser.valueOf(twitter4jStatus.getUser())); + tweet.setText(twitter4jStatus.getText()); + tweet.setTime(twitter4jStatus.getCreatedAt().getTime()); + tweet.setRetweetCount(twitter4jStatus.getRetweetCount()); + + return tweet; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java new file mode 100644 index 0000000..20bfe83 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java @@ -0,0 +1,41 @@ +package model; + +import twitter4j.User; + +/** + * Class represents Twitter User object. + */ +public class TwitterUser { + private Long id; + private String name; + + public TwitterUser(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + /** + * Factory method to convert twitter4j.User object to internal model - TwitterUser object. + * @param twitter4jUser twitter4j.User object + * @return TwitterUser object + */ + public static TwitterUser valueOf(User twitter4jUser) { + return new TwitterUser(twitter4jUser.getId(), twitter4jUser.getName()); + } + + @Override + public String toString() { + return "TwitterUser{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java new file mode 100644 index 0000000..292d6f5 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java @@ -0,0 +1,49 @@ +package utils; + +import twitter4j.*; + +import static java.lang.Math.*; + +public final class GeoUtils { + + private GeoUtils() {} + + /** + * Finds twitter4j.Place object by place name. + * @param twitter initialized twitter instance + * @param placeName name of place to search + * @return found twitter4j.Place object + * @throws TwitterException + */ + public static Place findPlaceByName(Twitter twitter, String placeName) throws TwitterException { + GeoQuery geoQuery = new GeoQuery((String)null); + geoQuery.setQuery(placeName); + // we need the only one place + geoQuery.setMaxResults(1); + ResponseList places = twitter.searchPlaces(geoQuery); + if (places.isEmpty()) { + throw new IllegalArgumentException("Place by name = '" + placeName + "' not found"); + } + return places.get(0); + } + + /** + * Calculates distance between two points based on their longitude and latitude. + * @see + * + * @param lat1 latitude of point_1 + * @param lon1 longitude of point_1 + * @param lat2 latitude of point_2 + * @param lon2 longitude of point_2 + * @return distance in miles + */ + public static double distanceBetweenTwoCoordinates(double lat1, double lon1, double lat2, double lon2) { + double theta = lon1 - lon2; + double dist = sin(toRadians(lat1)) * sin(toRadians(lat2)) + + cos(toRadians(lat1)) * cos(toRadians(lat2)) * cos(toRadians(theta)); + dist = acos(dist); + dist = toDegrees(dist); + dist = dist * 60 * 1.1515; + return dist; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java new file mode 100644 index 0000000..a99e25d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java @@ -0,0 +1,16 @@ +package utils; + +public final class TextUtils { + public static final String COLOR_RESET = "\u001B[0m"; + public static final String COLOR_BLUE = "\u001B[34m"; + + // to prevent instantiating + // this class must be used as static only + private TextUtils() {} + + public static String coloredText(String text, String color) { + return color + + text + + COLOR_RESET; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt new file mode 100644 index 0000000..95008c4 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt @@ -0,0 +1,11 @@ +TwitterStream - it's a console application to print the stream of tweets onto the screen +according to the specified conditions. + +Command usage: +java TwitterStream \ + [--query|-q ] \ + [--place|-p ] \ + [--stream|-s] \ + [--hideRetweets] \ + [--limit|-l ] \ + [--help|-h] diff --git a/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java b/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java new file mode 100644 index 0000000..4bb8dd4 --- /dev/null +++ b/projects/liza22/src/test/java/ru/mipt/diht/students/AppTest.java @@ -0,0 +1,38 @@ +package ru.mipt.diht.students; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} diff --git a/projects/pom.xml b/projects/pom.xml index 5d14966..5fc3c22 100644 --- a/projects/pom.xml +++ b/projects/pom.xml @@ -1,5 +1,5 @@ - + + 4.0.0 ru.mipt.diht.students @@ -30,7 +30,8 @@ dkhurtin ale3otik Pitovsky - + liza22 + @@ -133,4 +134,4 @@ - + \ No newline at end of file From 1e744a729ce57f270fd9b1971c349b113f45cb13 Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 00:19:29 +0300 Subject: [PATCH 02/17] checkstyle fixed --- .../main/java/ru/mipt/diht/students/App.java | 8 ++-- .../src/main/java/TwitterStream.java | 12 +++--- .../src/main/java/config/Arguments.java | 22 +++++------ .../src/main/java/config/TwitterConfig.java | 37 ++++++++++-------- .../core/handling/TweetHandlerFactory.java | 4 +- .../impl/PrintResultOfQueryTweetsHandler.java | 10 ++--- .../impl/PrintStreamOfTweetsHandler.java | 8 ++-- .../src/main/java/model/TwitterUser.java | 2 +- .../src/main/java/utils/GeoUtils.java | 12 +++--- .../src/main/java/utils/TextUtils.java | 8 ++-- ...1\203\320\272\321\206\320\270\321\217.txt" | Bin 0 -> 162 bytes 11 files changed, 62 insertions(+), 61 deletions(-) create mode 100644 "projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/~$\320\260\321\202\320\272\320\260\321\217 \320\270\320\275\321\201\321\202\321\200\321\203\320\272\321\206\320\270\321\217.txt" diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/App.java b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java index 38fae44..31d6fa9 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/App.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/App.java @@ -4,10 +4,8 @@ * Hello world! * */ -public class App -{ - public static void main( String[] args ) - { - System.out.println( "Hello World!" ); +public class App { + public static void main(String[] args) { + System.out.println("Hello World!"); } } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index 76f5418..c5aacc1 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -15,11 +15,13 @@ */ public class TwitterStream { - public static void main(String[] argsString) { + public static void main(final String[] argsString) { extractArguments(argsString); Arguments arguments = Arguments.getInstance(); - // In case of HELP page is requested, just print HELP file content and exit application + /* In case of HELP page is requested, + * just print HELP file content and exit application + */ if (arguments.isHelpRequest()) { printHelp(System.out); System.exit(0); @@ -48,7 +50,7 @@ public static void main(String[] argsString) { * Transforms arguments string to Arguments object with parsed fields. * @param argsString arguments strings from the input */ - private static void extractArguments(String[] argsString) { + private static void extractArguments(final String[] argsString) { JCommander jCommander = new JCommander(); jCommander.addObject(Arguments.getInstance()); jCommander.parse(argsString); @@ -62,7 +64,7 @@ private static void printHelp(OutputStream out) { try { byte[] buffer = new byte[1024]; try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { - for (int length; (length = input.read(buffer)) != -1; ) { + for (int length; (length = input.read(buffer)) != -1;) { out.write(buffer, 0, length); } } @@ -70,4 +72,4 @@ private static void printHelp(OutputStream out) { System.err.println("Problem with reading help file: \"" + e.getMessage() + "\""); } } -} +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java index 0a78225..ab151b4 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java @@ -10,14 +10,12 @@ * * @see http://jcommander.org/ */ -public class Arguments { +public final class Arguments { private static final Arguments INSTANCE = new Arguments(); private Arguments() {} - public static Arguments getInstance() { - return INSTANCE; - } + public static Arguments getInstance() {return INSTANCE;} @Parameter(names = {"--query", "-q"}, required = true, @@ -94,13 +92,13 @@ public boolean isVerboseMode() { @Override public String toString() { return "Arguments{" + - "keywords=" + keywords + - ", place='" + place + '\'' + - ", streamMode=" + streamMode + - ", hideRetweets=" + hideRetweets + - ", limitOfTweets=" + limitOfTweets + - ", helpRequest=" + helpRequest + - ", verboseMode=" + verbose + - '}'; + "keywords=" + keywords + + ", place='" + place + '\'' + + ", streamMode=" + streamMode + + ", hideRetweets=" + hideRetweets + + ", limitOfTweets=" + limitOfTweets + + ", helpRequest=" + helpRequest + + ", verboseMode=" + verbose + + '}'; } } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java index a34a176..9cee397 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java @@ -6,7 +6,7 @@ import java.io.*; -/** +/* * Class loads and holds Twitter Access configuration from file resource * and provides methods to get {@link twitter4j.conf.Configuration} and {@link twitter4j.auth.AccessToken} */ @@ -27,8 +27,7 @@ public TwitterConfig() { private void init() { File cfgFile = new File(Constants.TWITTER_CONFIG_FILE); - try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)))) - { + try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(cfgFile)))) { while (in.ready()) { String line = in.readLine(); int indexOfDelimiter = line.indexOf('='); @@ -37,7 +36,7 @@ private void init() { continue; } String propName = line.substring(0, indexOfDelimiter); - String propValue = line.substring(indexOfDelimiter+1, line.length()); + String propValue = line.substring(indexOfDelimiter + 1, line.length()); switch (propName) { case CONSUMER_KEY_PROP_NAME: consumerKey = propValue; @@ -65,19 +64,19 @@ private void init() { } private void validate() { - if (consumerKey == null || - consumerSecret == null || - accessToken == null || - accessTokenSecret == null) { + if (consumerKey == null + || consumerSecret == null + || accessToken == null + || accessTokenSecret == null) { throw new IllegalStateException("Twitter configuration file is incorrect"); } } - public AccessToken getAccessToken() { + public final AccessToken getAccessToken() { return new AccessToken(accessToken, accessTokenSecret); } - public Configuration getConfiguration() { + public final Configuration getConfiguration() { ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(). setOAuthConsumerKey(consumerKey). setOAuthConsumerSecret(consumerSecret). @@ -87,12 +86,16 @@ public Configuration getConfiguration() { } @Override - public String toString() { - return "TwitterConfig{" + - "consumerKey='" + consumerKey + '\'' + - ", consumerSecret='" + consumerSecret + '\'' + - ", accessToken='" + accessToken + '\'' + - ", accessTokenSecret='" + accessTokenSecret + '\'' + - '}'; + public final String toString() { + return "TwitterConfig{" + + "consumerKey='" + consumerKey + + '\'' + + ", consumerSecret='" + consumerSecret + + '\'' + + ", accessToken='" + accessToken + + '\'' + + ", accessTokenSecret='" + accessTokenSecret + + '\'' + + '}'; } } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java index 65cb51a..807bc25 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java @@ -4,9 +4,9 @@ import core.handling.impl.PrintStreamOfTweetsHandler; import model.Mode; -public class TweetHandlerFactory { +public final class TweetHandlerFactory { - private TweetHandlerFactory() {} + private TweetHandlerFactory() { } /** * Gets tweets handler depending on the working mode. diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java index 6854901..7004bac 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java @@ -21,17 +21,17 @@ public class PrintResultOfQueryTweetsHandler implements TweetHandler { private AtomicLong tweetCounter = new AtomicLong(0); - public PrintResultOfQueryTweetsHandler(PrintStream out) { - this.out = out; + public PrintResultOfQueryTweetsHandler(PrintStream outStream) { + this.out = outStream; } @Override - public void handle(Tweet tweet) { + public final void handle(Tweet tweet) { out.println("Tweet#" + tweetCounter.incrementAndGet() + ":"); out.println(formatTweet(tweet)); } - /** + /* * Print format is the following: * * If tweet IS NOT retweeted @@ -71,7 +71,7 @@ private static String getNickname(Tweet tweet) { return TextUtils.coloredText(nick, TextUtils.COLOR_BLUE); } - /** + /* * Time format is the following: * Время должно быть в формате: * "Только что" - если менее 2х минут назад diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java index 38b07fa..951b608 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java @@ -13,7 +13,7 @@ import java.util.TimerTask; import java.util.concurrent.atomic.AtomicLong; -/** +/* * This handler is used in STREAM mode of application. * It prints tweets every Constants.PRINT_TWEET_DELAY_SECS (by default every 1 second). * @@ -30,8 +30,8 @@ public class PrintStreamOfTweetsHandler implements TweetHandler { private boolean started = false; private AtomicLong tweetCounter = new AtomicLong(0); - public PrintStreamOfTweetsHandler(final PrintStream out) { - this.out = out; + public PrintStreamOfTweetsHandler(final PrintStream outStream) { + this.out = outStream; tweetQueue = new ArrayDeque<>(); } @@ -59,7 +59,7 @@ public void run() { } } - /** + /* * Print format is the following: * * If tweet IS NOT retweeted diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java index 20bfe83..85c1598 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java @@ -38,4 +38,4 @@ public String toString() { ", name='" + name + '\'' + '}'; } -} +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java index 292d6f5..e9f4b9a 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java @@ -6,9 +6,9 @@ public final class GeoUtils { - private GeoUtils() {} + private GeoUtils() { } - /** + /* * Finds twitter4j.Place object by place name. * @param twitter initialized twitter instance * @param placeName name of place to search @@ -16,7 +16,7 @@ private GeoUtils() {} * @throws TwitterException */ public static Place findPlaceByName(Twitter twitter, String placeName) throws TwitterException { - GeoQuery geoQuery = new GeoQuery((String)null); + GeoQuery geoQuery = new GeoQuery((String) null); geoQuery.setQuery(placeName); // we need the only one place geoQuery.setMaxResults(1); @@ -27,7 +27,7 @@ public static Place findPlaceByName(Twitter twitter, String placeName) throws Tw return places.get(0); } - /** + /* * Calculates distance between two points based on their longitude and latitude. * @see * @@ -39,8 +39,8 @@ public static Place findPlaceByName(Twitter twitter, String placeName) throws Tw */ public static double distanceBetweenTwoCoordinates(double lat1, double lon1, double lat2, double lon2) { double theta = lon1 - lon2; - double dist = sin(toRadians(lat1)) * sin(toRadians(lat2)) + - cos(toRadians(lat1)) * cos(toRadians(lat2)) * cos(toRadians(theta)); + double dist = sin(toRadians(lat1)) * sin(toRadians(lat2)) + + cos(toRadians(lat1)) * cos(toRadians(lat2)) * cos(toRadians(theta)); dist = acos(dist); dist = toDegrees(dist); dist = dist * 60 * 1.1515; diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java index a99e25d..e7f9304 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java @@ -6,11 +6,11 @@ public final class TextUtils { // to prevent instantiating // this class must be used as static only - private TextUtils() {} + private TextUtils() { } public static String coloredText(String text, String color) { - return color + - text + - COLOR_RESET; + return color + + text + + COLOR_RESET; } } diff --git "a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/~$\320\260\321\202\320\272\320\260\321\217 \320\270\320\275\321\201\321\202\321\200\321\203\320\272\321\206\320\270\321\217.txt" "b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/~$\320\260\321\202\320\272\320\260\321\217 \320\270\320\275\321\201\321\202\321\200\321\203\320\272\321\206\320\270\321\217.txt" new file mode 100644 index 0000000000000000000000000000000000000000..0ebf8fbd1362b5758a1d2024ba7e86bb95a56f28 GIT binary patch literal 162 zcmZR{$*f9bAQiAM Date: Thu, 17 Dec 2015 01:14:19 +0300 Subject: [PATCH 03/17] checkstyle fixed --- .../src/main/java/TwitterStream.java | 9 +++-- .../src/main/java/config/Arguments.java | 11 +++--- .../core/providing/TweetsProviderFactory.java | 4 +-- .../providing/impl/TweetsStreamProvider.java | 4 +-- .../java/core/quering/FilterQueryBuilder.java | 6 ++-- .../java/core/quering/SearchQueryBuilder.java | 12 +++---- .../src/main/java/model/Tweet.java | 34 +++++++++---------- .../src/main/java/model/TwitterUser.java | 21 ++++++------ 8 files changed, 53 insertions(+), 48 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index c5aacc1..e20af79 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -13,6 +13,9 @@ /** * Main Class. */ + +final int LINE_LENGTH = 1024; + public class TwitterStream { public static void main(final String[] argsString) { @@ -39,8 +42,8 @@ public static void main(final String[] argsString) { // start tweets providing and handling tweetsProvider.provide(tweetHandler); } catch (Exception e) { - System.err.println("Application TwitterStream has been occasionally crashed " + - "with error = \"" + e.getMessage() + "\""); + System.err.println("Application TwitterStream has been occasionally crashed " + + "with error = \"" + e.getMessage() + "\""); System.err.println("Application will be terminated with error code."); System.exit(1); } @@ -62,7 +65,7 @@ private static void extractArguments(final String[] argsString) { */ private static void printHelp(OutputStream out) { try { - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[LINE_LENGTH]; try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { for (int length; (length = input.read(buffer)) != -1;) { out.write(buffer, 0, length); diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java index ab151b4..fff104b 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java @@ -13,9 +13,9 @@ public final class Arguments { private static final Arguments INSTANCE = new Arguments(); - private Arguments() {} + private Arguments() { } - public static Arguments getInstance() {return INSTANCE;} + public static Arguments getInstance() { return INSTANCE; } @Parameter(names = {"--query", "-q"}, required = true, @@ -91,9 +91,10 @@ public boolean isVerboseMode() { @Override public String toString() { - return "Arguments{" + - "keywords=" + keywords - + ", place='" + place + '\'' + return "Arguments{" + + "keywords=" + keywords + + ", place='" + place + + '\'' + ", streamMode=" + streamMode + ", hideRetweets=" + hideRetweets + ", limitOfTweets=" + limitOfTweets diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java index c77911d..664dd46 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java @@ -7,9 +7,9 @@ /** * Tweets provider factory. */ -public class TweetsProviderFactory { +public final class TweetsProviderFactory { - private TweetsProviderFactory() {} + private TweetsProviderFactory() { } /** * Gets tweets provider depending on the working mode. diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java index e55b933..3164b8b 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java @@ -44,7 +44,7 @@ public void provide(TweetHandler handler) { } @Override - public void onStatus(Status status) { + public final void onStatus(Status status) { Tweet tweet = Tweet.valueOf(status); if (Arguments.getInstance().hideRetweets() && tweet.isRetweet()) { // skip this tweet @@ -54,7 +54,7 @@ public void onStatus(Status status) { } @Override - public void onException(Exception e) { + public final void onException(Exception e) { System.err.println("Twitter stream has been occasionally crashed with error: \"" + e.getMessage() + "\""); System.err.println("Try to reconnect... [timeout = " + Constants.RECONNECT_TIMEOUT_SECS + " secs]"); reconnect(); diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java index 6f3f890..b865b29 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java @@ -11,11 +11,11 @@ public class FilterQueryBuilder { private Twitter twitter; - public FilterQueryBuilder(Twitter twitter) { - this.twitter = twitter; + public FilterQueryBuilder(Twitter _twitter) { + this.twitter = _twitter; } - public FilterQuery buildQuery() { + public final FilterQuery buildQuery() { Arguments arguments = Arguments.getInstance(); FilterQuery query = new FilterQuery(); diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java index 70cd998..78a4685 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java @@ -16,11 +16,11 @@ public class SearchQueryBuilder { private Twitter twitter; - public SearchQueryBuilder(Twitter twitter) { - this.twitter = twitter; + public SearchQueryBuilder(Twitter _twitter) { + this.twitter = _twitter; } - public Query buildQuery() { + public final Query buildQuery() { Arguments arguments = Arguments.getInstance(); Query query = new Query(); // set query for tweets @@ -68,8 +68,8 @@ public static GeoLocation getCenter(GeoLocation[] vertices) { public static double getRadius(GeoLocation[] vertices) { List distances = new ArrayList<>(); // calculate distances between all vertices - for (int i = 0; i < vertices.length-1; i++) { - for (int j = i+1; j < vertices.length; j++) { + for (int i = 0; i < vertices.length - 1; i++) { + for (int j = i + 1; j < vertices.length; j++) { GeoLocation vertex1 = vertices[i]; GeoLocation vertex2 = vertices[j]; distances.add(GeoUtils.distanceBetweenTwoCoordinates( @@ -84,7 +84,7 @@ public static double getRadius(GeoLocation[] vertices) { return distances.get(0); } - public static double getArithmeticMean(double[] numbers){ + public static double getArithmeticMean(double[] numbers) { double sum = 0; for (double num : numbers) { sum += num; diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java index 972578f..b58dd7d 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java @@ -12,51 +12,51 @@ public class Tweet { private long retweetCount; private Tweet retweetedTweet; - public String getText() { + public final String getText() { return text; } - public void setText(String text) { - this.text = text; + public void setText(String tweetText) { + this.text = tweetText; } - public TwitterUser getAuthor() { + public final TwitterUser getAuthor() { return author; } - public void setAuthor(TwitterUser author) { - this.author = author; + public void setAuthor(TwitterUser tweetAuthor) { + this.author = tweetAuthor; } - public long getRetweetCount() { + public final long getRetweetCount() { return retweetCount; } - public void setRetweetCount(long retweetCount) { - this.retweetCount = retweetCount; + public void setRetweetCount(long count) { + this.retweetCount = count; } - public long getTime() { + public final long getTime() { return time; } - public void setTime(long time) { - this.time = time; + public void setTime(long tweetTime) { + this.time = tweetTime; } - public Tweet getRetweetedTweet() { + public final Tweet getRetweetedTweet() { return retweetedTweet; } - public void setRetweetedTweet(Tweet retweetedTweet) { - this.retweetedTweet = retweetedTweet; + public void setRetweetedTweet(Tweet retweeted) { + this.retweetedTweet = retweeted; } - public boolean isRetweet() { + public final boolean isRetweet() { return null != retweetedTweet; } - public boolean isNotRetweet() { + public final boolean isNotRetweet() { return !isRetweet(); } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java index 85c1598..692be37 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java @@ -9,16 +9,16 @@ public class TwitterUser { private Long id; private String name; - public TwitterUser(Long id, String name) { - this.id = id; - this.name = name; + public TwitterUser(Long userid, String username) { + this.id = userid; + this.name = username; } - public Long getId() { + public final Long getId() { return id; } - public String getName() { + public final String getName() { return name; } @@ -32,10 +32,11 @@ public static TwitterUser valueOf(User twitter4jUser) { } @Override - public String toString() { - return "TwitterUser{" + - "id=" + id + - ", name='" + name + '\'' + - '}'; + public final String toString() { + return "TwitterUser{" + + "id=" + id + + ", name='" + name + + '\'' + + '}'; } } \ No newline at end of file From 0dec5615431b284a64fcbe2107940abe9cdaad14 Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 01:33:37 +0300 Subject: [PATCH 04/17] checkstyle fixed --- .../liza22/TwitterStream/src/main/java/TwitterStream.java | 2 +- .../liza22/TwitterStream/src/main/java/config/Arguments.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index e20af79..68f95e9 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -14,7 +14,7 @@ * Main Class. */ -final int LINE_LENGTH = 1024; +public static final int LINE_LENGTH = 1024; public class TwitterStream { diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java index fff104b..461846a 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java @@ -15,7 +15,9 @@ public final class Arguments { private Arguments() { } - public static Arguments getInstance() { return INSTANCE; } + public static Arguments getInstance() { + return INSTANCE; + } @Parameter(names = {"--query", "-q"}, required = true, From 7061460f344fbbd4f0411520435431bdef53f236 Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 01:46:21 +0300 Subject: [PATCH 05/17] checkstyle --- .../liza22/TwitterStream/src/main/java/TwitterStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index 68f95e9..c4754d6 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -14,10 +14,10 @@ * Main Class. */ -public static final int LINE_LENGTH = 1024; - public class TwitterStream { + public static final int LINE_LENGTH = 1024; + public static void main(final String[] argsString) { extractArguments(argsString); Arguments arguments = Arguments.getInstance(); From 3cd199b3c8537c74ae274449e742ebabca52d7b4 Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 02:46:38 +0300 Subject: [PATCH 06/17] checkstyle fixed --- .../handling/impl/PrintResultOfQueryTweetsHandler.java | 10 +++++++--- .../core/handling/impl/PrintStreamOfTweetsHandler.java | 8 +++++--- .../core/providing/impl/TweetsByQueryProvider.java | 2 +- .../java/core/providing/impl/TweetsStreamProvider.java | 2 +- .../src/main/java/core/quering/FilterQueryBuilder.java | 4 ++-- .../src/main/java/core/quering/SearchQueryBuilder.java | 4 ++-- .../TwitterStream/src/main/java/model/Tweet.java | 2 +- .../TwitterStream/src/main/java/model/TwitterUser.java | 2 +- .../TwitterStream/src/main/java/utils/GeoUtils.java | 4 +++- 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java index 7004bac..3a9e129 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java @@ -16,7 +16,11 @@ * When new tweet is obtained (method 'handle' invoked) this handler prints * formatted representation of this new tweet. */ -public class PrintResultOfQueryTweetsHandler implements TweetHandler { +public final class PrintResultOfQueryTweetsHandler implements TweetHandler { + private static final int MILLI = 1_000; + private static final int SEC_IN_MIN = 60; + private static final int STRING_SIZE = 256; + private PrintStream out; private AtomicLong tweetCounter = new AtomicLong(0); @@ -48,7 +52,7 @@ public final void handle(Tweet tweet) { * @return text representation of tweet according to format */ private static String formatTweet(Tweet tweet) { - StringBuilder tweetView = new StringBuilder(256); + StringBuilder tweetView = new StringBuilder(STRING_SIZE); tweetView.append("----------------------------------------------------------------------------------------\n"); if (tweet.isNotRetweet()) { tweetView.append("[").append(formatTime(tweet.getTime())).append("] "). @@ -85,7 +89,7 @@ private static String getNickname(Tweet tweet) { */ private static String formatTime(long then) { long now = new Date().getTime(); - long diffInMinutes = (now - then) / 1_000 / 60; // milliseconds/1_000/60 = minutes + long diffInMinutes = (now - then) / MILLI / SEC_IN_MIN; if (diffInMinutes < 2) { return "Только что"; } else if (TimeUnit.MINUTES.toHours(diffInMinutes) < 1) { diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java index 951b608..87e6e9a 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java @@ -23,7 +23,9 @@ * In case when no available tweet in queue, it will print nothing or * Constants.NO_TWEET_MESSAGE in VERBOSE mode. */ -public class PrintStreamOfTweetsHandler implements TweetHandler { +public final class PrintStreamOfTweetsHandler implements TweetHandler { + public static final int STRING_SIZE = 256; + public static final int KILO = 1_000; private PrintStream out; private Queue tweetQueue; @@ -54,7 +56,7 @@ public void run() { } } } - }, 0, Constants.PRINT_TWEET_DELAY_SECS * 1_000); + }, 0, Constants.PRINT_TWEET_DELAY_SECS * KILO); started = true; } } @@ -76,7 +78,7 @@ public void run() { * @return text representation of tweet according to format */ private static String formatTweet(Tweet tweet) { - StringBuilder tweetView = new StringBuilder(256); + StringBuilder tweetView = new StringBuilder(STRING_SIZE); tweetView.append("----------------------------------------------------------------------------------------\n"); if (tweet.isNotRetweet()) { tweetView.append("@").append(getNickname(tweet)). diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java index 0de15dc..ba200c3 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java @@ -21,7 +21,7 @@ * internal Tweet objects, after that these tweets are sent to * handler. */ -public class TweetsByQueryProvider implements TweetsProvider { +public final class TweetsByQueryProvider implements TweetsProvider { private Twitter twitter; private Query query; diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java index 3164b8b..7324c53 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java @@ -22,7 +22,7 @@ * internal Tweet object performed, after that this Tweet sent * to the handler. */ -public class TweetsStreamProvider extends StatusAdapter implements TweetsProvider { +public final class TweetsStreamProvider extends StatusAdapter implements TweetsProvider { private Configuration configuration; private AccessToken accessToken; diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java index b865b29..1b13f1a 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java @@ -11,8 +11,8 @@ public class FilterQueryBuilder { private Twitter twitter; - public FilterQueryBuilder(Twitter _twitter) { - this.twitter = _twitter; + public FilterQueryBuilder(Twitter twiter) { + this.twitter = twiter; } public final FilterQuery buildQuery() { diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java index 78a4685..3948ad3 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java @@ -16,8 +16,8 @@ public class SearchQueryBuilder { private Twitter twitter; - public SearchQueryBuilder(Twitter _twitter) { - this.twitter = _twitter; + public SearchQueryBuilder(Twitter twiter) { + this.twitter = twiter; } public final Query buildQuery() { diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java index b58dd7d..4d0cc0c 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java @@ -5,7 +5,7 @@ /** * Class represents Tweet object. */ -public class Tweet { +public final class Tweet { private String text; private TwitterUser author; private long time; diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java index 692be37..a10e491 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java @@ -39,4 +39,4 @@ public final String toString() { + '\'' + '}'; } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java index e9f4b9a..662507b 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java @@ -5,6 +5,8 @@ import static java.lang.Math.*; public final class GeoUtils { + public static final int CONST1 = 60; + public static final double CONST2 = 1.1515; private GeoUtils() { } @@ -43,7 +45,7 @@ public static double distanceBetweenTwoCoordinates(double lat1, double lon1, dou + cos(toRadians(lat1)) * cos(toRadians(lat2)) * cos(toRadians(theta)); dist = acos(dist); dist = toDegrees(dist); - dist = dist * 60 * 1.1515; + dist = dist * CONST1 * CONST2; return dist; } } From 40120527686891efed5e8d8d6855aad00e42ff6d Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 02:57:10 +0300 Subject: [PATCH 07/17] checkstyle fixed --- .../TwitterStream/src/main/java/TwitterStream.java | 12 +++++++++--- .../impl/PrintResultOfQueryTweetsHandler.java | 2 +- .../core/providing/impl/TweetsStreamProvider.java | 4 ++-- .../TwitterStream/src/main/java/model/Tweet.java | 14 +++++++------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index c4754d6..527a28c 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -33,7 +33,12 @@ public static void main(final String[] argsString) { // read and initialize twitter configuration TwitterConfig twitterConfig = new TwitterConfig(); // define working mode of application - Mode workingMode = (arguments.isStreamMode()) ? Mode.STREAM : Mode.QUERY; + Mode workingMode; + if (arguments.isStreamMode()) { + workingMode = Mode.STREAM; + } else { + workingMode = Mode.QUERY; + } // get tweets provider for selected working mode and initialize this one TweetsProvider tweetsProvider = TweetsProviderFactory.getProvider(workingMode); tweetsProvider.init(twitterConfig); @@ -67,7 +72,8 @@ private static void printHelp(OutputStream out) { try { byte[] buffer = new byte[LINE_LENGTH]; try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { - for (int length; (length = input.read(buffer)) != -1;) { + for (int length; length != -1;) { + length = input.read(buffer); out.write(buffer, 0, length); } } @@ -75,4 +81,4 @@ private static void printHelp(OutputStream out) { System.err.println("Problem with reading help file: \"" + e.getMessage() + "\""); } } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java index 3a9e129..b244d2e 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java @@ -30,7 +30,7 @@ public PrintResultOfQueryTweetsHandler(PrintStream outStream) { } @Override - public final void handle(Tweet tweet) { + public void handle(Tweet tweet) { out.println("Tweet#" + tweetCounter.incrementAndGet() + ":"); out.println(formatTweet(tweet)); } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java index 7324c53..cc4e514 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java @@ -44,7 +44,7 @@ public void provide(TweetHandler handler) { } @Override - public final void onStatus(Status status) { + public void onStatus(Status status) { Tweet tweet = Tweet.valueOf(status); if (Arguments.getInstance().hideRetweets() && tweet.isRetweet()) { // skip this tweet @@ -54,7 +54,7 @@ public final void onStatus(Status status) { } @Override - public final void onException(Exception e) { + public void onException(Exception e) { System.err.println("Twitter stream has been occasionally crashed with error: \"" + e.getMessage() + "\""); System.err.println("Try to reconnect... [timeout = " + Constants.RECONNECT_TIMEOUT_SECS + " secs]"); reconnect(); diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java index 4d0cc0c..9ead43c 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java @@ -12,7 +12,7 @@ public final class Tweet { private long retweetCount; private Tweet retweetedTweet; - public final String getText() { + public String getText() { return text; } @@ -20,7 +20,7 @@ public void setText(String tweetText) { this.text = tweetText; } - public final TwitterUser getAuthor() { + public TwitterUser getAuthor() { return author; } @@ -28,7 +28,7 @@ public void setAuthor(TwitterUser tweetAuthor) { this.author = tweetAuthor; } - public final long getRetweetCount() { + public long getRetweetCount() { return retweetCount; } @@ -36,7 +36,7 @@ public void setRetweetCount(long count) { this.retweetCount = count; } - public final long getTime() { + public long getTime() { return time; } @@ -44,7 +44,7 @@ public void setTime(long tweetTime) { this.time = tweetTime; } - public final Tweet getRetweetedTweet() { + public Tweet getRetweetedTweet() { return retweetedTweet; } @@ -52,11 +52,11 @@ public void setRetweetedTweet(Tweet retweeted) { this.retweetedTweet = retweeted; } - public final boolean isRetweet() { + public boolean isRetweet() { return null != retweetedTweet; } - public final boolean isNotRetweet() { + public boolean isNotRetweet() { return !isRetweet(); } From d72dd651298d36821266a23fb7f2cddc50b7f1cd Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 03:44:33 +0300 Subject: [PATCH 08/17] pom.xml changed --- projects/liza22/pom.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml index 02e4233..29abee2 100644 --- a/projects/liza22/pom.xml +++ b/projects/liza22/pom.xml @@ -22,5 +22,19 @@ 3.8.1 test - + + org.twitter4j + twitter4j-core + [4.0,) + + + org.twitter4j + twitter4j-stream + [4.0,) + + + com.beust + jcommander + 1.48 + From 3016804442a3a544f5023b1c71faad06cf1baffd Mon Sep 17 00:00:00 2001 From: liza22 Date: Thu, 17 Dec 2015 03:53:31 +0300 Subject: [PATCH 09/17] fixed compilation --- .../liza22/TwitterStream/src/main/java/TwitterStream.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java index 527a28c..01aaba5 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java @@ -72,9 +72,10 @@ private static void printHelp(OutputStream out) { try { byte[] buffer = new byte[LINE_LENGTH]; try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { - for (int length; length != -1;) { - length = input.read(buffer); + int length = input.read(buffer); + while (length != -1) { out.write(buffer, 0, length); + length = input.read(buffer); } } } catch (IOException e) { From a81455674b4646e6f8b40adfd622aea12ebce034 Mon Sep 17 00:00:00 2001 From: liza22 Date: Fri, 18 Dec 2015 04:26:26 +0300 Subject: [PATCH 10/17] add CollectionsQL --- .../diht/students/liza22/collectionql/pom.xml | 39 +++ .../src/main/java/CollectionQuery.java | 42 +++ .../src/main/java/client/Statistics.java | 57 ++++ .../src/main/java/client/Student.java | 39 +++ .../src/main/java/client/StudentInfo.java | 58 ++++ .../src/main/java/library/api/Aggregates.java | 50 ++++ .../src/main/java/library/api/Conditions.java | 25 ++ .../java/library/api/OrderByConditions.java | 18 ++ .../src/main/java/library/api/Query.java | 29 ++ .../src/main/java/library/api/Source.java | 10 + .../src/main/java/library/api/Sources.java | 21 ++ .../main/java/library/core/QueryContext.java | 167 +++++++++++ .../src/main/java/library/core/QueryImpl.java | 125 ++++++++ .../main/java/library/core/QuerySource.java | 69 +++++ .../exceptions/IncorrectQueryException.java | 11 + .../library/core/model/GroupingCondition.java | 45 +++ .../library/core/model/SelectArgument.java | 83 ++++++ .../model/aggregation/AggregateFunction.java | 42 +++ .../aggregation/impl/AverageFunction.java | 24 ++ .../model/aggregation/impl/CountFunction.java | 21 ++ .../aggregation/impl/ExtremumFunction.java | 28 ++ .../model/aggregation/impl/MaxFunction.java | 18 ++ .../model/aggregation/impl/MinFunction.java | 18 ++ .../core/operations/OperationType.java | 27 ++ .../core/operations/QueryOperation.java | 44 +++ .../operations/QueryOperationFactory.java | 32 +++ .../impl/AbstractSelectOperation.java | 156 ++++++++++ .../operations/impl/DistinctOperation.java | 32 +++ .../impl/GroupingSelectOperation.java | 110 +++++++ .../core/operations/impl/HavingOperation.java | 28 ++ .../core/operations/impl/LimitOperation.java | 26 ++ .../operations/impl/OrderByOperation.java | 28 ++ .../impl/SimpleSelectOperation.java | 45 +++ .../core/operations/impl/UnionOperation.java | 29 ++ .../core/operations/impl/WhereOperation.java | 28 ++ .../java/library/core/utils/NumberUtils.java | 71 +++++ .../test/java/library/CorrectQueryTest.java | 270 ++++++++++++++++++ .../test/java/library/IncorrectQueryTest.java | 109 +++++++ 38 files changed, 2074 insertions(+) create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml new file mode 100644 index 0000000..9194c51 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + collection-ql + collection-ql + 1.0 + + + + org.apache.commons + commons-collections4 + 4.0 + + + + junit + junit + 4.4 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java new file mode 100644 index 0000000..61048f4 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java @@ -0,0 +1,42 @@ +import client.Statistics; +import client.Student; +import library.core.exceptions.IncorrectQueryException; + +import java.time.LocalDate; + +import static client.Student.student; +import static library.api.Aggregates.avg; +import static library.api.Aggregates.constant; +import static library.api.Aggregates.count; +import static library.api.Conditions.like; +import static library.api.OrderByConditions.asc; +import static library.api.OrderByConditions.desc; +import static library.api.Sources.from; +import static library.api.Sources.list; + +public class CollectionQuery { + + public static void main(String[] args) throws IncorrectQueryException { + final int const10 = 10; + final int const100 = 100; + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) + .where(like(Student::getName, ".*ov").and(s -> s.age() > const10)) + .groupBy(Student::getGroup) + .having(s -> s.getCount() > 0) + .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) + .limit(const100) + .union( + from(list(student("ivanov", LocalDate.parse("1985-08-06"), "494"))) + .selectDistinct(Statistics.class, constant("all"), count(s -> 1), avg(Student::age)) + ) + .execute(); + System.out.println(statistics); + } + +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java new file mode 100644 index 0000000..82f7063 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java @@ -0,0 +1,57 @@ +package client; + +public class Statistics { + + private final String group; + private final Long count; + private final Long age; + private final int const1 = 31; + + public final String getGroup() { + return group; + } + + public final Long getCount() { + return count; + } + + public final Long getAge() { + return age; + } + + public Statistics(String group1, Long count1, Long age1) { + this.group = group1; + this.count = count1; + this.age = age1; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Statistics that = (Statistics) o; + + if (!group.equals(that.group)) return false; + if (!count.equals(that.count)) return false; + return age.equals(that.age); + + } + + @Override + public final int hashCode() { + int result = group.hashCode(); + result = const1 * result + count.hashCode(); + result = const1 * result + age.hashCode(); + return result; + } + + @Override + public final String toString() { + return "Statistics{" + + "group=" + group + + ", count=" + count + + ", avg=" + age + + '}'; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java new file mode 100644 index 0000000..45b6a86 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java @@ -0,0 +1,39 @@ +package client; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +public class Student { + private final String name; + + private final LocalDate dateOfBirth; + + private final String group; + + public final String getName() { + return name; + } + + public Student(String name1, LocalDate dateOfBirth1, String group1) { + this.name = name1; + this.dateOfBirth = dateOfBirth1; + this.group = group1; + } + + public final LocalDate getDateOfBirth() { + return dateOfBirth; + } + + public final String getGroup() { + return group; + } + + public final long age() { + return ChronoUnit.YEARS.between(getDateOfBirth(), LocalDateTime.now()); + } + + public static Student student(String name1, LocalDate dateOfBirth1, String group1) { + return new Student(name1, dateOfBirth1, group1); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java new file mode 100644 index 0000000..eb7fbf7 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java @@ -0,0 +1,58 @@ +package client; + +public class StudentInfo { + private String name; + private String group; + private long age; + + public StudentInfo(String name1, String group1, Long age1) { + this.name = name1; + this.group = group1; + this.age = age1; + } + + public final String getName() { + return name; + } + + public final String getGroup() { + return group; + } + + public final long getAge() { + return age; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StudentInfo that = (StudentInfo) o; + + if (age != that.age) return false; + if (!name.equals(that.name)) return false; + return group.equals(that.group); + + } + + @Override + public final int hashCode() { + final int const31 = 31; + final int const32 = 32; + + int result = name.hashCode(); + result = const31 * result + group.hashCode(); + result = const31 * result + (int) (age ^ (age >>> const32)); + return result; + } + + @Override + public final String toString() { + return "StudentInfo{" + + "name=" + name + + ", group=" + group + + ", age=" + age + + '}'; + } + } \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java new file mode 100644 index 0000000..c30657b --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java @@ -0,0 +1,50 @@ +package library.api; + +import library.core.model.aggregation.AggregateFunction; +import library.core.model.aggregation.impl.AverageFunction; +import library.core.model.aggregation.impl.CountFunction; +import library.core.model.aggregation.impl.MaxFunction; +import library.core.model.aggregation.impl.MinFunction; + +import java.util.function.Function; + +/** + * Aggregate functions. + */ +public class Aggregates { + + public static AggregateFunction count(Function countingFunction) { + return new CountFunction<>(countingFunction); + } + + public static AggregateFunction avg(Function averageFunction) { + return new AverageFunction<>(averageFunction); + } + + public static AggregateFunction max(Function function) { + return new MaxFunction<>(function); + } + + public static AggregateFunction min(Function function) { + return new MinFunction<>(function); + } + + /** + * This function represents AggregateFunction stub and + * can be used in aggregate select statement. + * Provides always the same value - constant argument. + * + * @param constant to provide value + * @param source element type + * @param result element type + * @return function stub for constant value + */ + public static AggregateFunction constant(R constant) { + return new AggregateFunction(e -> constant) { + @Override + public R apply(Iterable elements) { + return constant; + } + }; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java new file mode 100644 index 0000000..72a132a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java @@ -0,0 +1,25 @@ +package library.api; + +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * "where" statement conditions. + */ +public class Conditions { + + public static Predicate like(Function source, String mask) { + Objects.requireNonNull(source); + Objects.requireNonNull(mask); + return t -> { + Objects.requireNonNull(t); + String actual = source.apply(t); + return actual.matches(mask.replace("%", ".*")); + }; + } + + public static Predicate not(Predicate original) { + return original.negate(); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java new file mode 100644 index 0000000..4cfd7ef --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java @@ -0,0 +1,18 @@ +package library.api; + +import java.util.Comparator; +import java.util.function.Function; + +/* + * "orderBy" helpers - comparators with asc and desc order based on lambda function + */ +public class OrderByConditions { + + public static Comparator asc(Function condition) { + return (o1, o2) -> condition.apply(o1).compareTo(condition.apply(o2)); + } + + public static Comparator desc(Function condition) { + return (o1, o2) -> condition.apply(o2).compareTo(condition.apply(o1)); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java new file mode 100644 index 0000000..c0723df --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java @@ -0,0 +1,29 @@ +package library.api; + +import library.core.exceptions.IncorrectQueryException; + +import java.util.Comparator; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Query builder class. + * @param result element type + * @param source element type + */ +public interface Query { + + Query where(Predicate whereCondition); + + Query groupBy(Function... groupByFunction); + + Query having(Predicate havingCondition); + + Query orderBy(Comparator... orderByComparators); + + Query limit(int limit); + + Query union(Query query); + + Iterable execute() throws IncorrectQueryException; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java new file mode 100644 index 0000000..db34973 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java @@ -0,0 +1,10 @@ +package library.api; + +import java.util.function.Function; + +public interface Source { + + Query select(Class resultClass, Function... arguments); + + Query selectDistinct(Class resultClass, Function... arguments); +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java new file mode 100644 index 0000000..45aa96a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java @@ -0,0 +1,21 @@ +package library.api; + +import library.core.QuerySource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * "from" statement sources. + */ +public class Sources { + + public static List list(T... elements) { + return new ArrayList<>(Arrays.asList(elements)); + } + + public static Source from(List list) { + return new QuerySource<>(list); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java new file mode 100644 index 0000000..21f2af1 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java @@ -0,0 +1,167 @@ +package library.core; + +import library.api.Query; +import library.core.model.GroupingCondition; +import library.core.model.SelectArgument; + +import java.util.*; +import java.util.function.Predicate; + +/** + * The most important class, which contains all information about executed query. + * + * This context is piped from one operation to another and shared between all operations. + * It plays the role of shared storage on the every step. + * + * @param result type + * @param source element type + */ +public final class QueryContext { + /** + * Source elements of query ("from" statement). + */ + private List source; + /** + * Result class in "select" statement. + */ + private Class resultClass; + /** + * Select arguments in "select" statement. + */ + private List> selectArguments; + /** + * Whether distinct select requested or not. + */ + private boolean distinct; + /** + * Predicate in "where" statement. + */ + private Predicate where; + /** + * Grouping conditions in "groupBy" statement. + */ + private List> groupingConditions; + /** + * Predicate in "having" statement. + */ + private Predicate having; + /** + * Ordered comparators in "orderBy" statement. + */ + private Comparator[] orderBy; + /** + * Limit of result rows. + */ + private int limit; + /** + * Joined queries by "union" statement. + */ + private LinkedList> unions; + /** + * Result of query execution. + */ + private LinkedList result; + + public List getSource() { + return source; + } + + public void setSource(List source1) { + this.source = source1; + } + + public Class getResultClass() { + return resultClass; + } + + public void setResultClass(Class resultClass1) { + this.resultClass = resultClass1; + } + + + public List> getSelectArguments() { + return selectArguments; + } + + public void setSelectArguments(List> selectArguments1) { + this.selectArguments = selectArguments1; + } + + public boolean isDistinct() { + return distinct; + } + + public void setDistinct(boolean distinct1) { + this.distinct = distinct1; + } + + public Predicate getWhere() { + return where; + } + + public void setWhere(Predicate where1) { + this.where = where1; + } + + public List> getGroupingConditions() { + return groupingConditions; + } + + public void setGroupingConditions(List> groupingConditions1) { + this.groupingConditions = groupingConditions1; + } + + public Predicate getHaving() { + return having; + } + + public void setHaving(Predicate having1) { + this.having = having1; + } + + public Comparator[] getOrderBy() { + return orderBy; + } + + public void setOrderBy(Comparator[] orderBy1) { + this.orderBy = orderBy1; + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit1) { + this.limit = limit1; + } + + public List> getUnions() { + return unions; + } + + public void addUnion(Query union) { + if (unions == null) { + this.unions = new LinkedList<>(); + } + unions.add(union); + } + + public List getResult() { + return result; + } + + public void setResult(List result1) { + this.result = new LinkedList<>(result1); + } + + public void addResult(List result1) { + if (this.result == null) { + this.result = new LinkedList<>(); + } + this.result.addAll(0, result1); + } + + public boolean isGroupingQuery() { + return groupingConditions != null; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java new file mode 100644 index 0000000..91f1c6b --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java @@ -0,0 +1,125 @@ +package library.core; + +import library.api.Query; +import library.core.exceptions.IncorrectQueryException; +import library.core.model.GroupingCondition; +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; +import library.core.operations.QueryOperationFactory; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Class implements all functionality of Query interface. + * + * The main idea is: + * for each query statement the arguments are set to QueryContext + * and the corresponding operation is included in QueryOperationsChain. + * + * When method "execute" invoked all operations are ordered by + * their priority and executed bit by bit by using common Query context. + * + * @param result element type + * @param source element type + */ +public final class QueryImpl implements Query { + private final QueryContext queryContext; + private final List queryOperationsChain; + + public QueryImpl(QueryContext queryContext1) { + Objects.requireNonNull(queryContext1); + this.queryContext = queryContext1; + this.queryOperationsChain = new LinkedList<>(); + } + + @Override + public Query where(Predicate whereCondition) { + Objects.requireNonNull(whereCondition); + queryContext.setWhere(whereCondition); + queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.WHERE_OP)); + return this; + } + + @Override + public Query groupBy(Function... groupByConditions) { + if (groupByConditions.length == 0) { + throw new IllegalArgumentException("GroupBy statement without condition(-s)"); + } + List> groupingConditions = + IntStream.range(0, groupByConditions.length) + .mapToObj(i -> new GroupingCondition<>(i, groupByConditions[i])) + .sorted((a1, a2) -> (Integer.compare(a1.getOrder(), a2.getOrder()))) + .collect(Collectors.toList()); + queryContext.setGroupingConditions(groupingConditions); + return this; + } + + @Override + public Query having(Predicate havingCondition) { + Objects.requireNonNull(havingCondition); + queryContext.setHaving(havingCondition); + queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.HAVING_OP)); + return this; + } + + @Override + public Query orderBy(Comparator... orderByComparators) { + if (orderByComparators.length == 0) { + throw new IllegalArgumentException("OrderBy statement without comparator(-s)"); + } + queryContext.setOrderBy(orderByComparators); + queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.ORDER_BY_OP)); + return this; + } + + @Override + public Query limit(int limit) { + if (limit <= 0) { + throw new IllegalArgumentException("limit must be positive"); + } + queryContext.setLimit(limit); + queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.LIMIT_OP)); + return this; + } + + @Override + public Query union(Query query) { + Objects.requireNonNull(query); + queryContext.addUnion(query); + QueryOperation unionOp = QueryOperationFactory.getOperationByType(OperationType.UNION_OP); + if (!queryOperationsChain.contains(unionOp)) { + queryOperationsChain.add(unionOp); + } + return this; + } + + @Override + public Iterable execute() throws IncorrectQueryException { + // here will be fun ! + + // add select operation to chain of query operations + QueryOperation selectOperation = queryContext.isGroupingQuery() + ? QueryOperationFactory.getOperationByType(OperationType.GROUPING_SELECT_OP) + : QueryOperationFactory.getOperationByType(OperationType.SIMPLE_SELECT_OP); + queryOperationsChain.add(selectOperation); + if (queryContext.isDistinct()) { + queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.DISTINCT_OP)); + } + + // order operations by their order number + Collections.sort(queryOperationsChain, QueryOperation.ORDER_COMPARATOR); + // validate every statement before execution + for (QueryOperation op : queryOperationsChain) { + op.validate(queryContext); + } + // execute every operation step by step + for (QueryOperation op : queryOperationsChain) { + op.execute(queryContext); + } + return queryContext.getResult(); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java new file mode 100644 index 0000000..d232686 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java @@ -0,0 +1,69 @@ +package library.core; + +import library.api.Query; +import library.api.Source; +import library.core.model.SelectArgument; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Class represents the head point of query building. + * + * To start build query a user must create QuerySource object + * and invoke select[Distinct] method to get Query object. + * + * When select[Distinct] method invoked, it creates new + * QueryContext and Query object, fills it by "select" statement + * parameters and return Query instance to requester. + * + * @param source element type + */ +public final class QuerySource implements Source { + private List sourceList; + + public QuerySource(List sourceList1) { + Objects.requireNonNull(sourceList1); + if (sourceList1.isEmpty()) { + throw new IllegalArgumentException("Source collection must not be null"); + } + this.sourceList = sourceList1; + } + + @Override + public Query select(Class resultClass, Function... arguments) { + QueryContext queryContext = buildQueryContext(resultClass, arguments); + queryContext.setDistinct(false); + return new QueryImpl<>(queryContext); + } + + @Override + public Query selectDistinct(Class resultClass, Function... arguments) { + QueryContext queryContext = buildQueryContext(resultClass, arguments); + queryContext.setDistinct(true); + return new QueryImpl<>(queryContext); + } + + private QueryContext buildQueryContext(Class resultClass, Function... arguments) { + Objects.requireNonNull(resultClass); + if (arguments.length == 0) { + throw new IllegalArgumentException("The list of select arguments must not be empty"); + } + QueryContext queryContext = new QueryContext<>(); + queryContext.setSource(sourceList); + queryContext.setResultClass(resultClass); + + // create SelectArgument objects and store in sorted list + List> selectArguments = + IntStream.range(0, arguments.length) + .mapToObj(i -> new SelectArgument<>(i, arguments[i])) + .sorted((a1, a2) -> (Integer.compare(a1.getOrder(), a2.getOrder()))) + .collect(Collectors.toList()); + queryContext.setSelectArguments(Collections.unmodifiableList(selectArguments)); + return queryContext; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java new file mode 100644 index 0000000..a739546 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java @@ -0,0 +1,11 @@ +package library.core.exceptions; + +/** + * Checked exception to notify about incorrect query syntax. + */ +public class IncorrectQueryException extends Exception { + + public IncorrectQueryException(String description) { + super(description); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java new file mode 100644 index 0000000..132fce0 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java @@ -0,0 +1,45 @@ +package library.core.model; + +import java.util.Map; +import java.util.function.Function; + +/** + * Class wraps and keeps full information about a grouping condition in query's groupBy statement. + * @param source element type + */ +public class GroupingCondition { + /** + * Order of this condition. + */ + private int order; + /** + * Transformation function - labmda or aggregate function. + */ + private Function function; + /** + * Calculated values of this function for each source element (rows). + * These values are used to create groups of elements (rows). + */ + private Map groupedValues; + + public GroupingCondition(int order1, Function function1) { + this.order = order1; + this.function = function1; + } + + public final int getOrder() { + return order; + } + + public final Function getFunction() { + return function; + } + + public final Map getGroupedValues() { + return groupedValues; + } + + public final void setGroupedValues(Map groupedValues1) { + this.groupedValues = groupedValues1; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java new file mode 100644 index 0000000..f1c514b --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java @@ -0,0 +1,83 @@ +package library.core.model; + +import library.core.model.aggregation.AggregateFunction; + +import java.util.Map; +import java.util.function.Function; + +/** + * Class wraps and keeps full information about a select argument in query. + * @param source element type + */ +public class SelectArgument { + /** + * Order of this argument in query. + */ + private int order; + /** + * Transformation function - lambda or aggregate function. + */ + private Function function; + /** + * Argument value in case of argument is aggregate. + */ + private Object aggregatedValue; + /** + * Argument values mapped to source elements (rows) in case of argument is not aggregate. + */ + private Map values; + /** + * Class type of select argument. + * Used to find result class constructor with required signature. + */ + private Class valueClazz; + + public SelectArgument(int order1, Function function1) { + this.order = order1; + this.function = function1; + } + + public final int getOrder() { + return order; + } + + public final Function getFunction() { + return function; + } + + public final Object getAggregatedValue() { + return aggregatedValue; + } + + public final void setAggregateValue(Object aggregatedValue1) { + this.aggregatedValue = aggregatedValue1; + } + + public final Map getValues() { + return values; + } + + public final void setValues(Map values1) { + this.values = values1; + } + + public final boolean isAggregate() { + return (function instanceof AggregateFunction); + } + + public final AggregateFunction getAggregateFunction() { + if (isAggregate()) { + return (AggregateFunction) function; + } else { + throw new IllegalStateException("This argument is not aggregated"); + } + } + + public final Class getValueClazz() { + return valueClazz; + } + + public final void setValueClazz(Class valueClazz1) { + this.valueClazz = valueClazz1; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java new file mode 100644 index 0000000..8d1da5e --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java @@ -0,0 +1,42 @@ +package library.core.model.aggregation; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Aggregate function. + * @param source element type + * @param result of single function transformation type + * @param aggregated result type + */ +public abstract class AggregateFunction implements Function { + private Function singleFunction; + + public AggregateFunction(Function singleFunction1) { + Objects.requireNonNull(singleFunction1); + this.singleFunction = singleFunction1; + } + + /** + * Because function is aggregate, this applies on many elements, e.g. collection. + * @param elements set of elements to be applied by this aggregate function + * @return aggregation result + */ + public abstract A apply(Iterable elements); + + @Override + public final R apply(S t) { + // delegate single element transformation + return singleFunction.apply(t); + } + + @Override + public final Function compose(Function before) { + throw new UnsupportedOperationException(); + } + + @Override + public final Function andThen(Function after) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java new file mode 100644 index 0000000..9f8eb99 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java @@ -0,0 +1,24 @@ +package library.core.model.aggregation.impl; + +import library.core.model.aggregation.AggregateFunction; +import library.core.utils.NumberUtils; + +import java.util.function.Function; + +public class AverageFunction extends AggregateFunction { + + public AverageFunction(Function singleFunction) { + super(singleFunction); + } + + @Override + public final R apply(Iterable elements) { + long count = 0L; + Number sum = 0; + for (S element : elements) { + count++; + sum = NumberUtils.SUM_NUMBERS.apply(apply(element), sum); + } + return (R) NumberUtils.DIV_NUMBERS.apply(sum, count); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java new file mode 100644 index 0000000..064bf6d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java @@ -0,0 +1,21 @@ +package library.core.model.aggregation.impl; + +import library.core.model.aggregation.AggregateFunction; + +import java.util.function.Function; +import java.util.stream.StreamSupport; + +public class CountFunction extends AggregateFunction { + + public CountFunction(Function singleFunction) { + super(singleFunction); + } + + @Override + public final Long apply(Iterable elements) { + // start stream, filter only not null elements and count them + return StreamSupport.stream(elements.spliterator(), false). + filter(e -> e != null). + count(); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java new file mode 100644 index 0000000..75ad113 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java @@ -0,0 +1,28 @@ +package library.core.model.aggregation.impl; + +import library.core.model.aggregation.AggregateFunction; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public abstract class ExtremumFunction extends AggregateFunction { + + public ExtremumFunction(Function singleFunction) { + super(singleFunction); + } + + @Override + public final R apply(Iterable elements) { + // collect all values (results of transformation function) + List values = new ArrayList<>(); + for (S element : elements) { + R value = this.apply(element); + values.add(value); + } + // search max or min value and return this one + return findExtremum(values); + } + + protected abstract R findExtremum(List values); +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java new file mode 100644 index 0000000..e527862 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java @@ -0,0 +1,18 @@ +package library.core.model.aggregation.impl; + +import library.core.utils.NumberUtils; + +import java.util.List; +import java.util.function.Function; + +public class MaxFunction extends ExtremumFunction { + + public MaxFunction(Function singleFunction) { + super(singleFunction); + } + + @Override + protected final R findExtremum(List values) { + return values.stream().max(NumberUtils.COMPARE_NUMBERS::apply).get(); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java new file mode 100644 index 0000000..1ee3ec6 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java @@ -0,0 +1,18 @@ +package library.core.model.aggregation.impl; + +import library.core.utils.NumberUtils; + +import java.util.List; +import java.util.function.Function; + +public class MinFunction extends ExtremumFunction { + + public MinFunction(Function singleFunction) { + super(singleFunction); + } + + @Override + protected final R findExtremum(List values) { + return values.stream().min(NumberUtils.COMPARE_NUMBERS::apply).get(); + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java new file mode 100644 index 0000000..14cfd6a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java @@ -0,0 +1,27 @@ +package library.core.operations; + +public enum OperationType { + WHERE_OP (1), + SIMPLE_SELECT_OP (2), + GROUPING_SELECT_OP (2), + HAVING_OP (3), + ORDER_BY_OP (4), + LIMIT_OP (5), + DISTINCT_OP (6), + UNION_OP (10); + + /** + * Order of operation to be invoked in a query execution sequence. + */ + private int order; + + OperationType(int order1) { + this.order = order1; + } + + public int getOrder() { + return order; + } + + +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java new file mode 100644 index 0000000..d7ca9d7 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java @@ -0,0 +1,44 @@ +package library.core.operations; + +import library.core.QueryContext; +import library.core.exceptions.IncorrectQueryException; + +import java.util.Comparator; + +/** + * Class represents one query operation, such as "select", "orderBy" and etc. + */ +public interface QueryOperation { + + /** + * Comparator to compare QueryOperation instances by their order. + */ + Comparator ORDER_COMPARATOR = + (o1, o2) -> Integer.compare(o1.getType().getOrder(), o2.getType().getOrder()); + + /** + * @return type of query operation + */ + OperationType getType(); + + /** + * Validates query context before execution this operation. + * By default do nothing. + * @param queryContext execution query context + * @param result type + * @param source elements type + * @throws IncorrectQueryException in case of any incorrect in query found + */ + default void validate(final QueryContext queryContext) throws IncorrectQueryException { + // by default do nothing + } + + /** + * Main method which executes this query operation. + * @param queryContext execution query context + * @param result type + * @param source elements type + * @throws IncorrectQueryException in case of any incorrect in query found + */ + void execute(final QueryContext queryContext) throws IncorrectQueryException; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java new file mode 100644 index 0000000..303dd57 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java @@ -0,0 +1,32 @@ +package library.core.operations; + +import library.core.operations.impl.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * Factory for QueryOperation instances. + */ +public class QueryOperationFactory { + private static final Map operationInstances; + static { + operationInstances = new HashMap<>(); + operationInstances.put(OperationType.WHERE_OP, new WhereOperation()); + operationInstances.put(OperationType.SIMPLE_SELECT_OP, new SimpleSelectOperation()); + operationInstances.put(OperationType.GROUPING_SELECT_OP, new GroupingSelectOperation()); + operationInstances.put(OperationType.HAVING_OP, new HavingOperation()); + operationInstances.put(OperationType.ORDER_BY_OP, new OrderByOperation()); + operationInstances.put(OperationType.LIMIT_OP, new LimitOperation()); + operationInstances.put(OperationType.DISTINCT_OP, new DistinctOperation()); + operationInstances.put(OperationType.UNION_OP, new UnionOperation()); + } + + /** + * @param type requested query operation type + * @return query operation instance by requested type + */ + public static QueryOperation getOperationByType(OperationType type) { + return operationInstances.get(type); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java new file mode 100644 index 0000000..6fb2ff6 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java @@ -0,0 +1,156 @@ +package library.core.operations.impl; + +import library.core.model.SelectArgument; +import library.core.model.aggregation.AggregateFunction; +import library.core.operations.QueryOperation; +import library.core.QueryContext; +import library.core.exceptions.IncorrectQueryException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Abstract SelectOperation class which contains main functionality to + * do select statement. + * This class has a common part of SimpleSelect and GroupingSelect + * operations. + */ +public abstract class AbstractSelectOperation implements QueryOperation { + + @Override + public void validate(QueryContext queryContext) throws IncorrectQueryException { + List> selectArguments = queryContext.getSelectArguments(); + if (selectArguments == null || selectArguments.isEmpty()) { + throw new IncorrectQueryException("Select statement must have arguments"); + } + for (SelectArgument argument : selectArguments) { + if (argument.getFunction() == null) { + throw new IncorrectQueryException("Select arguments are incorrect"); + } + } + } + + protected List doSelect(List sourceElements, QueryContext queryContext) throws IncorrectQueryException { + List> selectArguments = queryContext.getSelectArguments(); + List> notAggregateArgs = selectArguments.stream(). + filter(a -> !a.isAggregate()). + collect(Collectors.toList()); + List> aggregateArgs = selectArguments.stream(). + filter(a -> a.isAggregate()). + collect(Collectors.toList()); + + // Step#1: calculate value for each select argument + calculateAggregateArguments(sourceElements, aggregateArgs); + calculateNotAggregateArguments(sourceElements, notAggregateArgs); + + // Step#2: create result class instances by using calculated + // in step#1 values of select arguments + Class resultClass = queryContext.getResultClass(); + Class[] constructorArgTypes = getConstructorParameterTypes(selectArguments); + try { + Constructor resultClassConstructor = resultClass.getDeclaredConstructor(constructorArgTypes); + List results = null; + if (!notAggregateArgs.isEmpty() && aggregateArgs.isEmpty()) { + // simple select without aggregations and grouping + // just calculate all select arguments for each source element + results = calculateResult(sourceElements, resultClassConstructor, notAggregateArgs); + } + if (notAggregateArgs.isEmpty() && !aggregateArgs.isEmpty()) { + // exceptional case when all select arguments are aggregate functions + // and no any grouping, so result will be just one row + R result = calculateOnlyAggregatedResult(resultClassConstructor, aggregateArgs); + results = Collections.singletonList(result); + } else if (!notAggregateArgs.isEmpty() && !aggregateArgs.isEmpty()) { + // case when aggregate function in arguments exist + // and not-aggregate also - suppose that they are grouping arguments + // suppose that source elements belong to only one group + // thus we can calculate all results and get first row, because + // the other will be the same + R result = calculateMixedResult(sourceElements.get(0), resultClassConstructor, selectArguments); + results = Collections.singletonList(result); + } + return results; + } catch (NoSuchMethodException e) { + throw new IncorrectQueryException("Constructor of result class = " + resultClass + + " with arg types = " + Arrays.toString(constructorArgTypes) + + " not found"); + } + } + + protected void calculateNotAggregateArguments(List sourceElements, List> selectArguments) { + for (SelectArgument selectArgument : selectArguments) { + // apply function for each element of source and store to map [element <-> value] + Map elementValues = new HashMap<>(sourceElements.size()); + for (S element : sourceElements) { + Object value = selectArgument.getFunction().apply(element); + elementValues.put(element, value); + if (selectArgument.getValueClazz() == null) { + selectArgument.setValueClazz(value.getClass()); + } + } + selectArgument.setValues(elementValues); + } + } + + protected void calculateAggregateArguments(List sourceElements, List> selectArguments) { + for (SelectArgument selectArgument : selectArguments) { + AggregateFunction aggregateFunction = selectArgument.getAggregateFunction(); + Object aggregateValue = aggregateFunction.apply(sourceElements); + selectArgument.setAggregateValue(aggregateValue); + selectArgument.setValueClazz(aggregateValue.getClass()); + } + } + + protected List calculateResult(List sourceElements, Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { + try { + List results = new ArrayList<>(sourceElements.size()); + for (S sourceElement : sourceElements) { + R resultElement = convertToResultObject(resultClassConstructor, sourceElement, selectArguments); + results.add(resultElement); + } + return results; + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); + } + } + + protected R calculateOnlyAggregatedResult(Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { + try { + return convertToResultObject(resultClassConstructor, null, selectArguments); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); + } + } + + protected R calculateMixedResult(S sourceElement, Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { + try { + return convertToResultObject(resultClassConstructor, sourceElement, selectArguments); + } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { + throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); + } + } + + protected static Class[] getConstructorParameterTypes(List> arguments) { + Class[] types = new Class[arguments.size()]; + // arguments are supposed to be sorted by order + for (int i = 0; i < arguments.size(); i++) { + types[i] = arguments.get(i).getValueClazz(); + } + return types; + } + + protected static R convertToResultObject(Constructor resultConstructor, S source, List> selectArguments) + throws IllegalAccessException, InvocationTargetException, InstantiationException { + Object[] constructorArguments = new Object[selectArguments.size()]; + for (int i = 0; i < selectArguments.size(); i++) { + SelectArgument selectArgument = selectArguments.get(i); + Object value = (selectArgument.isAggregate()) + ? selectArgument.getAggregatedValue() + : selectArgument.getValues().get(source); + constructorArguments[i] = value; + } + return resultConstructor.newInstance(constructorArguments); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java new file mode 100644 index 0000000..e55bc3f --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java @@ -0,0 +1,32 @@ +package library.core.operations.impl; + +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; +import library.core.QueryContext; + +import java.util.*; + +public final class DistinctOperation implements QueryOperation { + + @Override + public OperationType getType() { + return OperationType.DISTINCT_OP; + } + + @Override + public void execute(QueryContext queryContext) { + // filter duplicates + List result = queryContext.getResult(); + // iterate by list of results and remove duplicated elements + // HashSet used because it can contain the only unique elements + Set distinctElements = new HashSet<>(result.size()); + for (Iterator iterator = result.iterator(); iterator.hasNext();) { + R element = iterator.next(); + if (!distinctElements.contains(element)) { + distinctElements.add(element); + } else { + iterator.remove(); + } + } + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java new file mode 100644 index 0000000..8645d3f --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java @@ -0,0 +1,110 @@ +package library.core.operations.impl; + +import library.core.exceptions.IncorrectQueryException; +import library.core.model.GroupingCondition; +import library.core.model.SelectArgument; +import library.core.operations.OperationType; +import library.core.QueryContext; + +import java.util.*; + +/** + * This type of operation used when select query is grouping. + * Some additional preparations are required before do select + * for each group of elements. + */ +public final class GroupingSelectOperation extends AbstractSelectOperation { + + @Override + public OperationType getType() { + return OperationType.GROUPING_SELECT_OP; + } + + @Override + public void validate(QueryContext queryContext) throws IncorrectQueryException { + super.validate(queryContext); + // check that select arguments consist of aggregate functions or grouping conditions only + List> selectArguments = queryContext.getSelectArguments(); + List> groupingConditions = queryContext.getGroupingConditions(); + long aggregateFunctionsCnt = selectArguments.stream().filter(SelectArgument::isAggregate).count(); + long simpleFunctionsCnt = selectArguments.size() - aggregateFunctionsCnt; + if (simpleFunctionsCnt != groupingConditions.size()) { + throw new IncorrectQueryException("The only grouping expressions or aggregate functions " + + "are permitted in grouping select query."); + } + } + + @Override + public void execute(QueryContext queryContext) throws IncorrectQueryException { + List sourceElements = queryContext.getSource(); + // in case when all rows have been filtered out + if (sourceElements.isEmpty()) { + return; + } + + // Step#1: calculate grouping value for each source element + List> groupingConditions = queryContext.getGroupingConditions(); + calculateGroupingConditionValues(sourceElements, groupingConditions); + + // Step#2: grouping source elements + Map> groupsOfElements = groupElementsByConditions(sourceElements, groupingConditions); + + // Step#3: calculate select argument for each group of elements separately + for (String groupKey : groupsOfElements.keySet()) { + List groupElements = groupsOfElements.get(groupKey); + List groupResults = doSelect(groupElements, queryContext); + queryContext.addResult(groupResults); + } + } + + private Map> groupElementsByConditions(List sourceElements, List> conditions) { + // for each source element the groupKey is calculated + Map> groups = new HashMap<>(); + for (S element : sourceElements) { + String groupKey = calculateGroupKeyOfElement(element, conditions); + List groupElements = groups.get(groupKey); + if (groupElements == null) { + groupElements = new ArrayList<>(); + groups.put(groupKey, groupElements); + } + groupElements.add(element); + } + return groups; + } + + /* + * GroupKey consists of hashcodes of condition values for this element + * like "84141-14515-6111" in case of 3 grouping conditions and + * hashcode(condition_1_value) = 84141, hashcode(condition_2_value) = 14515, hashcode(condition_3_value) = 6111 + * elements with same groupKey belongs to the same group + * + * @param element source element for which groupKey has to be calculated + * @param conditions list of groupBy conditions + * @param source element type + * @return calculated GroupKey for this element + */ + private static String calculateGroupKeyOfElement(S element, List> conditions) { + StringBuilder groupKeyBuilder = new StringBuilder(); + boolean first = true; + for (GroupingCondition condition : conditions) { + if (!first) groupKeyBuilder.append("-"); + else first = false; + + Map values = condition.getGroupedValues(); + Object elValue = values.get(element); + groupKeyBuilder.append(elValue.hashCode()); + } + return groupKeyBuilder.toString(); + } + + private void calculateGroupingConditionValues(List sourceElements, List> groupingConditions) { + for (GroupingCondition condition : groupingConditions) { + Map elementValues = new HashMap<>(sourceElements.size()); + for (S element : sourceElements) { + Object groupedValue = condition.getFunction().apply(element); + elementValues.put(element, groupedValue); + } + condition.setGroupedValues(elementValues); + } + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java new file mode 100644 index 0000000..43d6e7b --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java @@ -0,0 +1,28 @@ +package library.core.operations.impl; + +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; +import library.core.QueryContext; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class HavingOperation implements QueryOperation { + + @Override + public final OperationType getType() { + return OperationType.HAVING_OP; + } + + @Override + public final void execute(QueryContext queryContext) { + // filter result list by using having predicate + Predicate havingCondition = queryContext.getHaving(); + List filteredResult = queryContext.getResult().stream(). + filter(havingCondition). + collect(Collectors.toList()); + // set filtered result + queryContext.setResult(filteredResult); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java new file mode 100644 index 0000000..0cb7b9e --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java @@ -0,0 +1,26 @@ +package library.core.operations.impl; + +import library.core.QueryContext; +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; + +import java.util.List; +import java.util.stream.Collectors; + +public class LimitOperation implements QueryOperation { + + @Override + public final OperationType getType() { + return OperationType.LIMIT_OP; + } + + @Override + public final void execute(QueryContext queryContext) { + // limit result list by using stream limit() method + List cutResult = queryContext.getResult().stream(). + limit(queryContext.getLimit()). + collect(Collectors.toList()); + // set cut result list ot context + queryContext.setResult(cutResult); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java new file mode 100644 index 0000000..fb7b5e2 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java @@ -0,0 +1,28 @@ +package library.core.operations.impl; + +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; +import library.core.QueryContext; +import org.apache.commons.collections4.comparators.ComparatorChain; + +import java.util.Collections; +import java.util.Comparator; + +public class OrderByOperation implements QueryOperation { + + @Override + public final OperationType getType() { + return OperationType.ORDER_BY_OP; + } + + @Override + public final void execute(QueryContext queryContext) { + // Apache ComparatorChain used to create chain of comparators + // and order by this one + ComparatorChain comparatorChain = new ComparatorChain<>(); + for (Comparator orderByComparator : queryContext.getOrderBy()) { + comparatorChain.addComparator(orderByComparator); + } + Collections.sort(queryContext.getResult(), comparatorChain); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java new file mode 100644 index 0000000..1304271 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java @@ -0,0 +1,45 @@ +package library.core.operations.impl; + +import library.core.exceptions.IncorrectQueryException; +import library.core.model.SelectArgument; +import library.core.operations.OperationType; +import library.core.QueryContext; + +import java.util.List; + +/** + * This type of operation used when select query is not grouping. + */ +public class SimpleSelectOperation extends AbstractSelectOperation { + + @Override + public final OperationType getType() { + return OperationType.SIMPLE_SELECT_OP; + } + + @Override + public final void validate(QueryContext queryContext) throws IncorrectQueryException { + super.validate(queryContext); + // check that there is not aggregate functions at all in "select" statement + // or if exists, then all arguments must be aggregate functions + // because this type of query doesn't have GroupBy condition and + // simple expressions are not permitted in "select" statement + List> selectArguments = queryContext.getSelectArguments(); + long aggregateArgsCnt = selectArguments.stream().filter(SelectArgument::isAggregate).count(); + if (aggregateArgsCnt != 0 && aggregateArgsCnt != selectArguments.size()) { + throw new IncorrectQueryException("The only grouping expressions or aggregate functions " + + "are permitted in select query with aggregate functions."); + } + } + + @Override + public final void execute(QueryContext queryContext) throws IncorrectQueryException { + List sourceElements = queryContext.getSource(); + // in case when all rows have been filtered out + if (sourceElements.isEmpty()) { + return; + } + List results = doSelect(sourceElements, queryContext); + queryContext.addResult(results); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java new file mode 100644 index 0000000..8932485 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java @@ -0,0 +1,29 @@ +package library.core.operations.impl; + +import library.api.Query; +import library.core.operations.OperationType; +import library.core.QueryContext; +import library.core.exceptions.IncorrectQueryException; +import library.core.operations.QueryOperation; + +import java.util.LinkedList; +import java.util.List; + +public final class UnionOperation implements QueryOperation { + + @Override + public OperationType getType() { + return OperationType.UNION_OP; + } + + @Override + public void execute(QueryContext queryContext) throws IncorrectQueryException { + for (Query unionQuery : queryContext.getUnions()) { + // execute union query, get its result list and put it into linked list + List unionQueryResult = new LinkedList<>(); + unionQuery.execute().forEach(unionQueryResult::add); + // after that this result is "glued" to our current result + queryContext.addResult(unionQueryResult); + } + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java new file mode 100644 index 0000000..92bb803 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java @@ -0,0 +1,28 @@ +package library.core.operations.impl; + +import library.core.operations.OperationType; +import library.core.operations.QueryOperation; +import library.core.QueryContext; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public final class WhereOperation implements QueryOperation { + + @Override + public OperationType getType() { + return OperationType.WHERE_OP; + } + + @Override + public void execute(QueryContext queryContext) { + Predicate whereCondition = queryContext.getWhere(); + // filter source list by using predicate from "where" statement + List filteredSource = queryContext.getSource().stream(). + filter(whereCondition). + collect(Collectors.toList()); + // set filtered source list to context + queryContext.setSource(filteredSource); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java new file mode 100644 index 0000000..5932c2a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java @@ -0,0 +1,71 @@ +package library.core.utils; + +import java.util.function.BiFunction; + +/** + * Util class to perform math operations with Number objects. + * + * Important assumption: + * A both arguments are supposed to having the same type, + * e.g. Long and Long, Integer and Integer and so on, + * because the real type is defined by the first argument only. + */ +public class NumberUtils { + + public static final BiFunction SUM_NUMBERS = (n1, n2) -> { + Class numberClazz = n1.getClass(); + if (numberClazz.equals(Integer.class)) { + return n1.intValue() + n2.intValue(); + } + else if (numberClazz.equals(Long.class)) { + return n1.longValue() + n2.longValue(); + } + else if (numberClazz.equals(Double.class)) { + return n1.doubleValue() + n2.doubleValue(); + } + else if (numberClazz.equals(Float.class)) { + return n1.floatValue() + n2.floatValue(); + } + else { + throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); + } + }; + + public static final BiFunction DIV_NUMBERS = (n1, n2) -> { + Class numberClazz = n1.getClass(); + if (numberClazz.equals(Integer.class)) { + return n1.intValue() / n2.intValue(); + } + else if (numberClazz.equals(Long.class)) { + return n1.longValue() / n2.longValue(); + } + else if (numberClazz.equals(Double.class)) { + return n1.doubleValue() / n2.doubleValue(); + } + else if (numberClazz.equals(Float.class)) { + return n1.floatValue() / n2.floatValue(); + } + else { + throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); + } + }; + + public static final BiFunction COMPARE_NUMBERS = (n1, n2) -> { + Class numberClazz = n1.getClass(); + if (numberClazz.equals(Integer.class)) { + return Integer.compare(n1.intValue(), n2.intValue()); + } + else if (numberClazz.equals(Long.class)) { + return Long.compare(n1.longValue(), n2.longValue()); + } + else if (numberClazz.equals(Double.class)) { + return Double.compare(n1.doubleValue(), n2.doubleValue()); + } + else if (numberClazz.equals(Float.class)) { + return Float.compare(n1.floatValue(), n2.floatValue()); + } + else { + throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); + } + }; +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java new file mode 100644 index 0000000..77d6d20 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java @@ -0,0 +1,270 @@ +package library; + +import client.Statistics; +import client.Student; +import library.api.Conditions; +import library.api.Sources; +import library.core.exceptions.IncorrectQueryException; +import org.junit.Test; + +import java.time.LocalDate; +import java.util.Iterator; + +import static client.Student.student; +import static library.api.Aggregates.*; +import static library.api.Conditions.like; +import static library.api.Conditions.not; +import static library.api.OrderByConditions.asc; +import static library.api.OrderByConditions.desc; +import static library.api.Sources.from; +import static library.api.Sources.list; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Main test class with many test samples. + */ +public class CorrectQueryTest { + + @Test + public void test_TaskSampleQuery() throws IncorrectQueryException { + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) + .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) + .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, constant("all"), count(s -> 1), avg(Student::age)) + ) + .execute(); + + Iterator resultIterator = statistics.iterator(); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("all", 1L, 30L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("494", 2L, 24L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); + assertFalse(resultIterator.hasNext()); + } + + @Test + public void test_SimpleSelectQuery() throws IncorrectQueryException { + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) + .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) + .execute(); + + Iterator resultIterator = statistics.iterator(); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 19L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 29L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); + assertFalse(resultIterator.hasNext()); + } + + @Test + public void test_SimpleSelectWithWhereQuery() throws IncorrectQueryException { + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) + .where(not(Conditions.like(Student::getName, ".*ov"))) + .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) + .execute(); + + Iterator resultIterator = statistics.iterator(); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); + assertFalse(resultIterator.hasNext()); + } + + @Test + public void test_SimpleSelectWithLimitQuery() throws IncorrectQueryException { + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) + .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) + .limit(2) + .execute(); + + Iterator resultIterator = statistics.iterator(); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 19L), resultIterator.next()); + assertTrue(resultIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 29L), resultIterator.next()); + assertFalse(resultIterator.hasNext()); + } + + @Test + public void test_SelectWithAggregateFunctionsWithoutGroupingQuery() throws IncorrectQueryException { + // find student with min age + Iterable minAge = + 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("1996-08-06"), "494"))) + .select(Statistics.class, constant("min"), constant(1L), min(Student::age)) + .execute(); + + Iterator minAgeIterator = minAge.iterator(); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("min", 1L, 19L), minAgeIterator.next()); + assertFalse(minAgeIterator.hasNext()); + + // find student with max age + Iterable maxAge = + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1946-08-06"), "495"), + student("petrov", LocalDate.parse("1996-08-06"), "494"))) + .select(Statistics.class, constant("max"), constant(1L), max(Student::age)) + .execute(); + + Iterator maxAgeIterator = maxAge.iterator(); + assertTrue(maxAgeIterator.hasNext()); + assertEquals(new Statistics("max", 1L, 69L), maxAgeIterator.next()); + assertFalse(maxAgeIterator.hasNext()); + + // find student with average age of all students + Iterable avgAge = + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1946-08-06"), "495"), + student("petrov", LocalDate.parse("1996-08-06"), "494"))) + .select(Statistics.class, constant("average"), constant(1L), avg(Student::age)) + .execute(); + + Iterator avgAgeIterator = avgAge.iterator(); + assertTrue(avgAgeIterator.hasNext()); + assertEquals(new Statistics("average", 1L, 36L), avgAgeIterator.next()); + assertFalse(avgAgeIterator.hasNext()); + + // count all students + Iterable cnt = + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1946-08-06"), "495"), + student("petrov", LocalDate.parse("1996-08-06"), "494"))) + .select(Statistics.class, constant("all"), count(s -> 1), avg(Student::age)) + .execute(); + + Iterator cntIterator = cnt.iterator(); + assertTrue(cntIterator.hasNext()); + assertEquals(new Statistics("all", 4L, 36L), cntIterator.next()); + assertFalse(cntIterator.hasNext()); + } + + @Test + public void test_SelectWithAggregateFunctionsWithGroupingQuery() throws IncorrectQueryException { + // find student with min age by groups + Iterable minAge = + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(s -> 1), min(Student::age)) + .groupBy(Student::getGroup) + .orderBy(asc(Statistics::getGroup)) + .execute(); + + Iterator minAgeIterator = minAge.iterator(); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("494", 2L, 19L), minAgeIterator.next()); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("495", 2L, 29L), minAgeIterator.next()); + assertFalse(minAgeIterator.hasNext()); + } + + @Test + public void test_SelectWithManyUnionsQuery() throws IncorrectQueryException { + // find student with min age + Iterable minAndMaxAndAvgAge = + 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("1996-08-06"), "494"))) + .select(Statistics.class, constant("min"), constant(1L), min(Student::age)) + .union( + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1946-08-06"), "495"), + student("petrov", LocalDate.parse("1996-08-06"), "494"))) + .select(Statistics.class, constant("max"), constant(1L), max(Student::age)) + ) + .union( + from(list( + student("ivanov", LocalDate.parse("1986-08-06"), "494"), + student("sidorov", LocalDate.parse("1986-08-06"), "495"), + student("smith", LocalDate.parse("1946-08-06"), "495"), + student("petrov", LocalDate.parse("1996-08-06"), "494"))) + .select(Statistics.class, constant("average"), constant(1L), avg(Student::age)) + ) + .execute(); + + Iterator minAndMaxAndAvgAgeIterator = minAndMaxAndAvgAge.iterator(); + assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); + assertEquals(new Statistics("average", 1L, 36L), minAndMaxAndAvgAgeIterator.next()); + assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); + assertEquals(new Statistics("max", 1L, 69L), minAndMaxAndAvgAgeIterator.next()); + assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); + assertEquals(new Statistics("min", 1L, 19L), minAndMaxAndAvgAgeIterator.next()); + assertFalse(minAndMaxAndAvgAgeIterator.hasNext()); + } + + @Test + public void test_SelectWithAggregateFunctionsWithManyGroupingConditionsQuery() throws IncorrectQueryException { + // group students by group and age and calculate their count + Iterable minAge = + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(s -> 1), Student::age) + .groupBy(Student::getGroup, Student::age) + .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) + .execute(); + + Iterator minAgeIterator = minAge.iterator(); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 19L), minAgeIterator.next()); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("494", 1L, 29L), minAgeIterator.next()); + assertTrue(minAgeIterator.hasNext()); + assertEquals(new Statistics("495", 2L, 29L), minAgeIterator.next()); + assertFalse(minAgeIterator.hasNext()); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java new file mode 100644 index 0000000..e698cec --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java @@ -0,0 +1,109 @@ +package library; + +import client.Statistics; +import client.Student; +import library.api.Conditions; +import library.core.exceptions.IncorrectQueryException; +import org.junit.Test; + +import java.time.LocalDate; + +import static client.Student.student; +import static library.api.Aggregates.avg; +import static library.api.Aggregates.count; +import static library.api.OrderByConditions.asc; +import static library.api.OrderByConditions.desc; +import static library.api.Sources.from; +import static library.api.Sources.list; + +/** + * Test class contains cases with incorrect library usage. + * + * In most such cases library should generate IncorrectQueryException, + * in other cases library generates IllegalArgumentException + * or NullPointerException in case when required argument is null. + */ +public class IncorrectQueryTest { + + @Test(expected = IllegalArgumentException.class) + public void test_EmptySourceQuery() throws IncorrectQueryException { + from(list(/* empty */)) + .select(Statistics.class) + .execute(); + } + + @Test(expected = IllegalArgumentException.class) + public void test_EmptyListOfSelectArgs() throws IncorrectQueryException { + from(list(new Object())).select(Object.class).execute(); + } + + @Test(expected = NullPointerException.class) + public void test_NullResultClass() throws IncorrectQueryException { + from(list(new Object())).select(null).execute(); + } + + @Test(expected = NullPointerException.class) + public void test_NullWhereStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).where(null).execute(); + } + + @Test(expected = NullPointerException.class) + public void test_NullOrderByStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).orderBy(null).execute(); + } + + @Test(expected = NullPointerException.class) + public void test_NullGroupByStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).groupBy(null).execute(); + } + + @Test(expected = IllegalArgumentException.class) + public void test_EmptyOrderByStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).orderBy().execute(); + } + + @Test(expected = IllegalArgumentException.class) + public void test_EmptyGroupByStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).groupBy().execute(); + } + + @Test(expected = IllegalArgumentException.class) + public void test_IncorrectLimitStatement() throws IncorrectQueryException { + from(list(new Object())).select(Object.class, o -> 1).limit(0).execute(); + } + + @Test(expected = IncorrectQueryException.class) + public void test_IncorrectSelectArguments() throws IncorrectQueryException { + // class Statistics doesn't have constructor with 2 arguments + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(Student::getGroup)) + .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) + .groupBy(Student::getGroup) + .having(s -> s.getCount() > 0) + .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) + .limit(100) + .execute(); + } + + @Test(expected = IncorrectQueryException.class) + public void test_AggregateAndNotAggregateFunctions_InNotGroupingQuery() throws IncorrectQueryException { + // select statement contains Student::getGroup but there is no such grouping function + // in such case the only aggregate functions or constant() are permitted + 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("1996-08-06"), "494"))) + .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) + .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) + .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) + .limit(100) + .execute(); + } +} \ No newline at end of file From 0d3ae55f56fbf5f9f6389df48829cea9797957df Mon Sep 17 00:00:00 2001 From: liza22 Date: Fri, 18 Dec 2015 22:08:11 +0300 Subject: [PATCH 11/17] delete cql --- .../diht/students/liza22/collectionql/pom.xml | 39 --- .../src/main/java/CollectionQuery.java | 42 --- .../src/main/java/client/Statistics.java | 57 ---- .../src/main/java/client/Student.java | 39 --- .../src/main/java/client/StudentInfo.java | 58 ---- .../src/main/java/library/api/Aggregates.java | 50 ---- .../src/main/java/library/api/Conditions.java | 25 -- .../java/library/api/OrderByConditions.java | 18 -- .../src/main/java/library/api/Query.java | 29 -- .../src/main/java/library/api/Source.java | 10 - .../src/main/java/library/api/Sources.java | 21 -- .../main/java/library/core/QueryContext.java | 167 ----------- .../src/main/java/library/core/QueryImpl.java | 125 -------- .../main/java/library/core/QuerySource.java | 69 ----- .../exceptions/IncorrectQueryException.java | 11 - .../library/core/model/GroupingCondition.java | 45 --- .../library/core/model/SelectArgument.java | 83 ------ .../model/aggregation/AggregateFunction.java | 42 --- .../aggregation/impl/AverageFunction.java | 24 -- .../model/aggregation/impl/CountFunction.java | 21 -- .../aggregation/impl/ExtremumFunction.java | 28 -- .../model/aggregation/impl/MaxFunction.java | 18 -- .../model/aggregation/impl/MinFunction.java | 18 -- .../core/operations/OperationType.java | 27 -- .../core/operations/QueryOperation.java | 44 --- .../operations/QueryOperationFactory.java | 32 --- .../impl/AbstractSelectOperation.java | 156 ---------- .../operations/impl/DistinctOperation.java | 32 --- .../impl/GroupingSelectOperation.java | 110 ------- .../core/operations/impl/HavingOperation.java | 28 -- .../core/operations/impl/LimitOperation.java | 26 -- .../operations/impl/OrderByOperation.java | 28 -- .../impl/SimpleSelectOperation.java | 45 --- .../core/operations/impl/UnionOperation.java | 29 -- .../core/operations/impl/WhereOperation.java | 28 -- .../java/library/core/utils/NumberUtils.java | 71 ----- .../test/java/library/CorrectQueryTest.java | 270 ------------------ .../test/java/library/IncorrectQueryTest.java | 109 ------- 38 files changed, 2074 deletions(-) delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml deleted file mode 100644 index 9194c51..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - collection-ql - collection-ql - 1.0 - - - - org.apache.commons - commons-collections4 - 4.0 - - - - junit - junit - 4.4 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.8 - 1.8 - - - - - \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java deleted file mode 100644 index 61048f4..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/CollectionQuery.java +++ /dev/null @@ -1,42 +0,0 @@ -import client.Statistics; -import client.Student; -import library.core.exceptions.IncorrectQueryException; - -import java.time.LocalDate; - -import static client.Student.student; -import static library.api.Aggregates.avg; -import static library.api.Aggregates.constant; -import static library.api.Aggregates.count; -import static library.api.Conditions.like; -import static library.api.OrderByConditions.asc; -import static library.api.OrderByConditions.desc; -import static library.api.Sources.from; -import static library.api.Sources.list; - -public class CollectionQuery { - - public static void main(String[] args) throws IncorrectQueryException { - final int const10 = 10; - final int const100 = 100; - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) - .where(like(Student::getName, ".*ov").and(s -> s.age() > const10)) - .groupBy(Student::getGroup) - .having(s -> s.getCount() > 0) - .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) - .limit(const100) - .union( - from(list(student("ivanov", LocalDate.parse("1985-08-06"), "494"))) - .selectDistinct(Statistics.class, constant("all"), count(s -> 1), avg(Student::age)) - ) - .execute(); - System.out.println(statistics); - } - -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java deleted file mode 100644 index 82f7063..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Statistics.java +++ /dev/null @@ -1,57 +0,0 @@ -package client; - -public class Statistics { - - private final String group; - private final Long count; - private final Long age; - private final int const1 = 31; - - public final String getGroup() { - return group; - } - - public final Long getCount() { - return count; - } - - public final Long getAge() { - return age; - } - - public Statistics(String group1, Long count1, Long age1) { - this.group = group1; - this.count = count1; - this.age = age1; - } - - @Override - public final boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Statistics that = (Statistics) o; - - if (!group.equals(that.group)) return false; - if (!count.equals(that.count)) return false; - return age.equals(that.age); - - } - - @Override - public final int hashCode() { - int result = group.hashCode(); - result = const1 * result + count.hashCode(); - result = const1 * result + age.hashCode(); - return result; - } - - @Override - public final String toString() { - return "Statistics{" - + "group=" + group - + ", count=" + count - + ", avg=" + age - + '}'; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java deleted file mode 100644 index 45b6a86..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/Student.java +++ /dev/null @@ -1,39 +0,0 @@ -package client; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; - -public class Student { - private final String name; - - private final LocalDate dateOfBirth; - - private final String group; - - public final String getName() { - return name; - } - - public Student(String name1, LocalDate dateOfBirth1, String group1) { - this.name = name1; - this.dateOfBirth = dateOfBirth1; - this.group = group1; - } - - public final LocalDate getDateOfBirth() { - return dateOfBirth; - } - - public final String getGroup() { - return group; - } - - public final long age() { - return ChronoUnit.YEARS.between(getDateOfBirth(), LocalDateTime.now()); - } - - public static Student student(String name1, LocalDate dateOfBirth1, String group1) { - return new Student(name1, dateOfBirth1, group1); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java deleted file mode 100644 index eb7fbf7..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/client/StudentInfo.java +++ /dev/null @@ -1,58 +0,0 @@ -package client; - -public class StudentInfo { - private String name; - private String group; - private long age; - - public StudentInfo(String name1, String group1, Long age1) { - this.name = name1; - this.group = group1; - this.age = age1; - } - - public final String getName() { - return name; - } - - public final String getGroup() { - return group; - } - - public final long getAge() { - return age; - } - - @Override - public final boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - StudentInfo that = (StudentInfo) o; - - if (age != that.age) return false; - if (!name.equals(that.name)) return false; - return group.equals(that.group); - - } - - @Override - public final int hashCode() { - final int const31 = 31; - final int const32 = 32; - - int result = name.hashCode(); - result = const31 * result + group.hashCode(); - result = const31 * result + (int) (age ^ (age >>> const32)); - return result; - } - - @Override - public final String toString() { - return "StudentInfo{" - + "name=" + name - + ", group=" + group - + ", age=" + age - + '}'; - } - } \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java deleted file mode 100644 index c30657b..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Aggregates.java +++ /dev/null @@ -1,50 +0,0 @@ -package library.api; - -import library.core.model.aggregation.AggregateFunction; -import library.core.model.aggregation.impl.AverageFunction; -import library.core.model.aggregation.impl.CountFunction; -import library.core.model.aggregation.impl.MaxFunction; -import library.core.model.aggregation.impl.MinFunction; - -import java.util.function.Function; - -/** - * Aggregate functions. - */ -public class Aggregates { - - public static AggregateFunction count(Function countingFunction) { - return new CountFunction<>(countingFunction); - } - - public static AggregateFunction avg(Function averageFunction) { - return new AverageFunction<>(averageFunction); - } - - public static AggregateFunction max(Function function) { - return new MaxFunction<>(function); - } - - public static AggregateFunction min(Function function) { - return new MinFunction<>(function); - } - - /** - * This function represents AggregateFunction stub and - * can be used in aggregate select statement. - * Provides always the same value - constant argument. - * - * @param constant to provide value - * @param source element type - * @param result element type - * @return function stub for constant value - */ - public static AggregateFunction constant(R constant) { - return new AggregateFunction(e -> constant) { - @Override - public R apply(Iterable elements) { - return constant; - } - }; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java deleted file mode 100644 index 72a132a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Conditions.java +++ /dev/null @@ -1,25 +0,0 @@ -package library.api; - -import java.util.Objects; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * "where" statement conditions. - */ -public class Conditions { - - public static Predicate like(Function source, String mask) { - Objects.requireNonNull(source); - Objects.requireNonNull(mask); - return t -> { - Objects.requireNonNull(t); - String actual = source.apply(t); - return actual.matches(mask.replace("%", ".*")); - }; - } - - public static Predicate not(Predicate original) { - return original.negate(); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java deleted file mode 100644 index 4cfd7ef..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/OrderByConditions.java +++ /dev/null @@ -1,18 +0,0 @@ -package library.api; - -import java.util.Comparator; -import java.util.function.Function; - -/* - * "orderBy" helpers - comparators with asc and desc order based on lambda function - */ -public class OrderByConditions { - - public static Comparator asc(Function condition) { - return (o1, o2) -> condition.apply(o1).compareTo(condition.apply(o2)); - } - - public static Comparator desc(Function condition) { - return (o1, o2) -> condition.apply(o2).compareTo(condition.apply(o1)); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java deleted file mode 100644 index c0723df..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Query.java +++ /dev/null @@ -1,29 +0,0 @@ -package library.api; - -import library.core.exceptions.IncorrectQueryException; - -import java.util.Comparator; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Query builder class. - * @param result element type - * @param source element type - */ -public interface Query { - - Query where(Predicate whereCondition); - - Query groupBy(Function... groupByFunction); - - Query having(Predicate havingCondition); - - Query orderBy(Comparator... orderByComparators); - - Query limit(int limit); - - Query union(Query query); - - Iterable execute() throws IncorrectQueryException; -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java deleted file mode 100644 index db34973..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Source.java +++ /dev/null @@ -1,10 +0,0 @@ -package library.api; - -import java.util.function.Function; - -public interface Source { - - Query select(Class resultClass, Function... arguments); - - Query selectDistinct(Class resultClass, Function... arguments); -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java deleted file mode 100644 index 45aa96a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/api/Sources.java +++ /dev/null @@ -1,21 +0,0 @@ -package library.api; - -import library.core.QuerySource; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * "from" statement sources. - */ -public class Sources { - - public static List list(T... elements) { - return new ArrayList<>(Arrays.asList(elements)); - } - - public static Source from(List list) { - return new QuerySource<>(list); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java deleted file mode 100644 index 21f2af1..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryContext.java +++ /dev/null @@ -1,167 +0,0 @@ -package library.core; - -import library.api.Query; -import library.core.model.GroupingCondition; -import library.core.model.SelectArgument; - -import java.util.*; -import java.util.function.Predicate; - -/** - * The most important class, which contains all information about executed query. - * - * This context is piped from one operation to another and shared between all operations. - * It plays the role of shared storage on the every step. - * - * @param result type - * @param source element type - */ -public final class QueryContext { - /** - * Source elements of query ("from" statement). - */ - private List source; - /** - * Result class in "select" statement. - */ - private Class resultClass; - /** - * Select arguments in "select" statement. - */ - private List> selectArguments; - /** - * Whether distinct select requested or not. - */ - private boolean distinct; - /** - * Predicate in "where" statement. - */ - private Predicate where; - /** - * Grouping conditions in "groupBy" statement. - */ - private List> groupingConditions; - /** - * Predicate in "having" statement. - */ - private Predicate having; - /** - * Ordered comparators in "orderBy" statement. - */ - private Comparator[] orderBy; - /** - * Limit of result rows. - */ - private int limit; - /** - * Joined queries by "union" statement. - */ - private LinkedList> unions; - /** - * Result of query execution. - */ - private LinkedList result; - - public List getSource() { - return source; - } - - public void setSource(List source1) { - this.source = source1; - } - - public Class getResultClass() { - return resultClass; - } - - public void setResultClass(Class resultClass1) { - this.resultClass = resultClass1; - } - - - public List> getSelectArguments() { - return selectArguments; - } - - public void setSelectArguments(List> selectArguments1) { - this.selectArguments = selectArguments1; - } - - public boolean isDistinct() { - return distinct; - } - - public void setDistinct(boolean distinct1) { - this.distinct = distinct1; - } - - public Predicate getWhere() { - return where; - } - - public void setWhere(Predicate where1) { - this.where = where1; - } - - public List> getGroupingConditions() { - return groupingConditions; - } - - public void setGroupingConditions(List> groupingConditions1) { - this.groupingConditions = groupingConditions1; - } - - public Predicate getHaving() { - return having; - } - - public void setHaving(Predicate having1) { - this.having = having1; - } - - public Comparator[] getOrderBy() { - return orderBy; - } - - public void setOrderBy(Comparator[] orderBy1) { - this.orderBy = orderBy1; - } - - public int getLimit() { - return limit; - } - - public void setLimit(int limit1) { - this.limit = limit1; - } - - public List> getUnions() { - return unions; - } - - public void addUnion(Query union) { - if (unions == null) { - this.unions = new LinkedList<>(); - } - unions.add(union); - } - - public List getResult() { - return result; - } - - public void setResult(List result1) { - this.result = new LinkedList<>(result1); - } - - public void addResult(List result1) { - if (this.result == null) { - this.result = new LinkedList<>(); - } - this.result.addAll(0, result1); - } - - public boolean isGroupingQuery() { - return groupingConditions != null; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java deleted file mode 100644 index 91f1c6b..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QueryImpl.java +++ /dev/null @@ -1,125 +0,0 @@ -package library.core; - -import library.api.Query; -import library.core.exceptions.IncorrectQueryException; -import library.core.model.GroupingCondition; -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; -import library.core.operations.QueryOperationFactory; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * Class implements all functionality of Query interface. - * - * The main idea is: - * for each query statement the arguments are set to QueryContext - * and the corresponding operation is included in QueryOperationsChain. - * - * When method "execute" invoked all operations are ordered by - * their priority and executed bit by bit by using common Query context. - * - * @param result element type - * @param source element type - */ -public final class QueryImpl implements Query { - private final QueryContext queryContext; - private final List queryOperationsChain; - - public QueryImpl(QueryContext queryContext1) { - Objects.requireNonNull(queryContext1); - this.queryContext = queryContext1; - this.queryOperationsChain = new LinkedList<>(); - } - - @Override - public Query where(Predicate whereCondition) { - Objects.requireNonNull(whereCondition); - queryContext.setWhere(whereCondition); - queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.WHERE_OP)); - return this; - } - - @Override - public Query groupBy(Function... groupByConditions) { - if (groupByConditions.length == 0) { - throw new IllegalArgumentException("GroupBy statement without condition(-s)"); - } - List> groupingConditions = - IntStream.range(0, groupByConditions.length) - .mapToObj(i -> new GroupingCondition<>(i, groupByConditions[i])) - .sorted((a1, a2) -> (Integer.compare(a1.getOrder(), a2.getOrder()))) - .collect(Collectors.toList()); - queryContext.setGroupingConditions(groupingConditions); - return this; - } - - @Override - public Query having(Predicate havingCondition) { - Objects.requireNonNull(havingCondition); - queryContext.setHaving(havingCondition); - queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.HAVING_OP)); - return this; - } - - @Override - public Query orderBy(Comparator... orderByComparators) { - if (orderByComparators.length == 0) { - throw new IllegalArgumentException("OrderBy statement without comparator(-s)"); - } - queryContext.setOrderBy(orderByComparators); - queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.ORDER_BY_OP)); - return this; - } - - @Override - public Query limit(int limit) { - if (limit <= 0) { - throw new IllegalArgumentException("limit must be positive"); - } - queryContext.setLimit(limit); - queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.LIMIT_OP)); - return this; - } - - @Override - public Query union(Query query) { - Objects.requireNonNull(query); - queryContext.addUnion(query); - QueryOperation unionOp = QueryOperationFactory.getOperationByType(OperationType.UNION_OP); - if (!queryOperationsChain.contains(unionOp)) { - queryOperationsChain.add(unionOp); - } - return this; - } - - @Override - public Iterable execute() throws IncorrectQueryException { - // here will be fun ! - - // add select operation to chain of query operations - QueryOperation selectOperation = queryContext.isGroupingQuery() - ? QueryOperationFactory.getOperationByType(OperationType.GROUPING_SELECT_OP) - : QueryOperationFactory.getOperationByType(OperationType.SIMPLE_SELECT_OP); - queryOperationsChain.add(selectOperation); - if (queryContext.isDistinct()) { - queryOperationsChain.add(QueryOperationFactory.getOperationByType(OperationType.DISTINCT_OP)); - } - - // order operations by their order number - Collections.sort(queryOperationsChain, QueryOperation.ORDER_COMPARATOR); - // validate every statement before execution - for (QueryOperation op : queryOperationsChain) { - op.validate(queryContext); - } - // execute every operation step by step - for (QueryOperation op : queryOperationsChain) { - op.execute(queryContext); - } - return queryContext.getResult(); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java deleted file mode 100644 index d232686..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/QuerySource.java +++ /dev/null @@ -1,69 +0,0 @@ -package library.core; - -import library.api.Query; -import library.api.Source; -import library.core.model.SelectArgument; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * Class represents the head point of query building. - * - * To start build query a user must create QuerySource object - * and invoke select[Distinct] method to get Query object. - * - * When select[Distinct] method invoked, it creates new - * QueryContext and Query object, fills it by "select" statement - * parameters and return Query instance to requester. - * - * @param source element type - */ -public final class QuerySource implements Source { - private List sourceList; - - public QuerySource(List sourceList1) { - Objects.requireNonNull(sourceList1); - if (sourceList1.isEmpty()) { - throw new IllegalArgumentException("Source collection must not be null"); - } - this.sourceList = sourceList1; - } - - @Override - public Query select(Class resultClass, Function... arguments) { - QueryContext queryContext = buildQueryContext(resultClass, arguments); - queryContext.setDistinct(false); - return new QueryImpl<>(queryContext); - } - - @Override - public Query selectDistinct(Class resultClass, Function... arguments) { - QueryContext queryContext = buildQueryContext(resultClass, arguments); - queryContext.setDistinct(true); - return new QueryImpl<>(queryContext); - } - - private QueryContext buildQueryContext(Class resultClass, Function... arguments) { - Objects.requireNonNull(resultClass); - if (arguments.length == 0) { - throw new IllegalArgumentException("The list of select arguments must not be empty"); - } - QueryContext queryContext = new QueryContext<>(); - queryContext.setSource(sourceList); - queryContext.setResultClass(resultClass); - - // create SelectArgument objects and store in sorted list - List> selectArguments = - IntStream.range(0, arguments.length) - .mapToObj(i -> new SelectArgument<>(i, arguments[i])) - .sorted((a1, a2) -> (Integer.compare(a1.getOrder(), a2.getOrder()))) - .collect(Collectors.toList()); - queryContext.setSelectArguments(Collections.unmodifiableList(selectArguments)); - return queryContext; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java deleted file mode 100644 index a739546..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/exceptions/IncorrectQueryException.java +++ /dev/null @@ -1,11 +0,0 @@ -package library.core.exceptions; - -/** - * Checked exception to notify about incorrect query syntax. - */ -public class IncorrectQueryException extends Exception { - - public IncorrectQueryException(String description) { - super(description); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java deleted file mode 100644 index 132fce0..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/GroupingCondition.java +++ /dev/null @@ -1,45 +0,0 @@ -package library.core.model; - -import java.util.Map; -import java.util.function.Function; - -/** - * Class wraps and keeps full information about a grouping condition in query's groupBy statement. - * @param source element type - */ -public class GroupingCondition { - /** - * Order of this condition. - */ - private int order; - /** - * Transformation function - labmda or aggregate function. - */ - private Function function; - /** - * Calculated values of this function for each source element (rows). - * These values are used to create groups of elements (rows). - */ - private Map groupedValues; - - public GroupingCondition(int order1, Function function1) { - this.order = order1; - this.function = function1; - } - - public final int getOrder() { - return order; - } - - public final Function getFunction() { - return function; - } - - public final Map getGroupedValues() { - return groupedValues; - } - - public final void setGroupedValues(Map groupedValues1) { - this.groupedValues = groupedValues1; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java deleted file mode 100644 index f1c514b..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/SelectArgument.java +++ /dev/null @@ -1,83 +0,0 @@ -package library.core.model; - -import library.core.model.aggregation.AggregateFunction; - -import java.util.Map; -import java.util.function.Function; - -/** - * Class wraps and keeps full information about a select argument in query. - * @param source element type - */ -public class SelectArgument { - /** - * Order of this argument in query. - */ - private int order; - /** - * Transformation function - lambda or aggregate function. - */ - private Function function; - /** - * Argument value in case of argument is aggregate. - */ - private Object aggregatedValue; - /** - * Argument values mapped to source elements (rows) in case of argument is not aggregate. - */ - private Map values; - /** - * Class type of select argument. - * Used to find result class constructor with required signature. - */ - private Class valueClazz; - - public SelectArgument(int order1, Function function1) { - this.order = order1; - this.function = function1; - } - - public final int getOrder() { - return order; - } - - public final Function getFunction() { - return function; - } - - public final Object getAggregatedValue() { - return aggregatedValue; - } - - public final void setAggregateValue(Object aggregatedValue1) { - this.aggregatedValue = aggregatedValue1; - } - - public final Map getValues() { - return values; - } - - public final void setValues(Map values1) { - this.values = values1; - } - - public final boolean isAggregate() { - return (function instanceof AggregateFunction); - } - - public final AggregateFunction getAggregateFunction() { - if (isAggregate()) { - return (AggregateFunction) function; - } else { - throw new IllegalStateException("This argument is not aggregated"); - } - } - - public final Class getValueClazz() { - return valueClazz; - } - - public final void setValueClazz(Class valueClazz1) { - this.valueClazz = valueClazz1; - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java deleted file mode 100644 index 8d1da5e..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/AggregateFunction.java +++ /dev/null @@ -1,42 +0,0 @@ -package library.core.model.aggregation; - -import java.util.Objects; -import java.util.function.Function; - -/** - * Aggregate function. - * @param source element type - * @param result of single function transformation type - * @param aggregated result type - */ -public abstract class AggregateFunction implements Function { - private Function singleFunction; - - public AggregateFunction(Function singleFunction1) { - Objects.requireNonNull(singleFunction1); - this.singleFunction = singleFunction1; - } - - /** - * Because function is aggregate, this applies on many elements, e.g. collection. - * @param elements set of elements to be applied by this aggregate function - * @return aggregation result - */ - public abstract A apply(Iterable elements); - - @Override - public final R apply(S t) { - // delegate single element transformation - return singleFunction.apply(t); - } - - @Override - public final Function compose(Function before) { - throw new UnsupportedOperationException(); - } - - @Override - public final Function andThen(Function after) { - throw new UnsupportedOperationException(); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java deleted file mode 100644 index 9f8eb99..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/AverageFunction.java +++ /dev/null @@ -1,24 +0,0 @@ -package library.core.model.aggregation.impl; - -import library.core.model.aggregation.AggregateFunction; -import library.core.utils.NumberUtils; - -import java.util.function.Function; - -public class AverageFunction extends AggregateFunction { - - public AverageFunction(Function singleFunction) { - super(singleFunction); - } - - @Override - public final R apply(Iterable elements) { - long count = 0L; - Number sum = 0; - for (S element : elements) { - count++; - sum = NumberUtils.SUM_NUMBERS.apply(apply(element), sum); - } - return (R) NumberUtils.DIV_NUMBERS.apply(sum, count); - } -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java deleted file mode 100644 index 064bf6d..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/CountFunction.java +++ /dev/null @@ -1,21 +0,0 @@ -package library.core.model.aggregation.impl; - -import library.core.model.aggregation.AggregateFunction; - -import java.util.function.Function; -import java.util.stream.StreamSupport; - -public class CountFunction extends AggregateFunction { - - public CountFunction(Function singleFunction) { - super(singleFunction); - } - - @Override - public final Long apply(Iterable elements) { - // start stream, filter only not null elements and count them - return StreamSupport.stream(elements.spliterator(), false). - filter(e -> e != null). - count(); - } -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java deleted file mode 100644 index 75ad113..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/ExtremumFunction.java +++ /dev/null @@ -1,28 +0,0 @@ -package library.core.model.aggregation.impl; - -import library.core.model.aggregation.AggregateFunction; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -public abstract class ExtremumFunction extends AggregateFunction { - - public ExtremumFunction(Function singleFunction) { - super(singleFunction); - } - - @Override - public final R apply(Iterable elements) { - // collect all values (results of transformation function) - List values = new ArrayList<>(); - for (S element : elements) { - R value = this.apply(element); - values.add(value); - } - // search max or min value and return this one - return findExtremum(values); - } - - protected abstract R findExtremum(List values); -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java deleted file mode 100644 index e527862..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MaxFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package library.core.model.aggregation.impl; - -import library.core.utils.NumberUtils; - -import java.util.List; -import java.util.function.Function; - -public class MaxFunction extends ExtremumFunction { - - public MaxFunction(Function singleFunction) { - super(singleFunction); - } - - @Override - protected final R findExtremum(List values) { - return values.stream().max(NumberUtils.COMPARE_NUMBERS::apply).get(); - } -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java deleted file mode 100644 index 1ee3ec6..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/model/aggregation/impl/MinFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -package library.core.model.aggregation.impl; - -import library.core.utils.NumberUtils; - -import java.util.List; -import java.util.function.Function; - -public class MinFunction extends ExtremumFunction { - - public MinFunction(Function singleFunction) { - super(singleFunction); - } - - @Override - protected final R findExtremum(List values) { - return values.stream().min(NumberUtils.COMPARE_NUMBERS::apply).get(); - } -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java deleted file mode 100644 index 14cfd6a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/OperationType.java +++ /dev/null @@ -1,27 +0,0 @@ -package library.core.operations; - -public enum OperationType { - WHERE_OP (1), - SIMPLE_SELECT_OP (2), - GROUPING_SELECT_OP (2), - HAVING_OP (3), - ORDER_BY_OP (4), - LIMIT_OP (5), - DISTINCT_OP (6), - UNION_OP (10); - - /** - * Order of operation to be invoked in a query execution sequence. - */ - private int order; - - OperationType(int order1) { - this.order = order1; - } - - public int getOrder() { - return order; - } - - -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java deleted file mode 100644 index d7ca9d7..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperation.java +++ /dev/null @@ -1,44 +0,0 @@ -package library.core.operations; - -import library.core.QueryContext; -import library.core.exceptions.IncorrectQueryException; - -import java.util.Comparator; - -/** - * Class represents one query operation, such as "select", "orderBy" and etc. - */ -public interface QueryOperation { - - /** - * Comparator to compare QueryOperation instances by their order. - */ - Comparator ORDER_COMPARATOR = - (o1, o2) -> Integer.compare(o1.getType().getOrder(), o2.getType().getOrder()); - - /** - * @return type of query operation - */ - OperationType getType(); - - /** - * Validates query context before execution this operation. - * By default do nothing. - * @param queryContext execution query context - * @param result type - * @param source elements type - * @throws IncorrectQueryException in case of any incorrect in query found - */ - default void validate(final QueryContext queryContext) throws IncorrectQueryException { - // by default do nothing - } - - /** - * Main method which executes this query operation. - * @param queryContext execution query context - * @param result type - * @param source elements type - * @throws IncorrectQueryException in case of any incorrect in query found - */ - void execute(final QueryContext queryContext) throws IncorrectQueryException; -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java deleted file mode 100644 index 303dd57..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/QueryOperationFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package library.core.operations; - -import library.core.operations.impl.*; - -import java.util.HashMap; -import java.util.Map; - -/** - * Factory for QueryOperation instances. - */ -public class QueryOperationFactory { - private static final Map operationInstances; - static { - operationInstances = new HashMap<>(); - operationInstances.put(OperationType.WHERE_OP, new WhereOperation()); - operationInstances.put(OperationType.SIMPLE_SELECT_OP, new SimpleSelectOperation()); - operationInstances.put(OperationType.GROUPING_SELECT_OP, new GroupingSelectOperation()); - operationInstances.put(OperationType.HAVING_OP, new HavingOperation()); - operationInstances.put(OperationType.ORDER_BY_OP, new OrderByOperation()); - operationInstances.put(OperationType.LIMIT_OP, new LimitOperation()); - operationInstances.put(OperationType.DISTINCT_OP, new DistinctOperation()); - operationInstances.put(OperationType.UNION_OP, new UnionOperation()); - } - - /** - * @param type requested query operation type - * @return query operation instance by requested type - */ - public static QueryOperation getOperationByType(OperationType type) { - return operationInstances.get(type); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java deleted file mode 100644 index 6fb2ff6..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/AbstractSelectOperation.java +++ /dev/null @@ -1,156 +0,0 @@ -package library.core.operations.impl; - -import library.core.model.SelectArgument; -import library.core.model.aggregation.AggregateFunction; -import library.core.operations.QueryOperation; -import library.core.QueryContext; -import library.core.exceptions.IncorrectQueryException; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.stream.Collectors; - -/** - * Abstract SelectOperation class which contains main functionality to - * do select statement. - * This class has a common part of SimpleSelect and GroupingSelect - * operations. - */ -public abstract class AbstractSelectOperation implements QueryOperation { - - @Override - public void validate(QueryContext queryContext) throws IncorrectQueryException { - List> selectArguments = queryContext.getSelectArguments(); - if (selectArguments == null || selectArguments.isEmpty()) { - throw new IncorrectQueryException("Select statement must have arguments"); - } - for (SelectArgument argument : selectArguments) { - if (argument.getFunction() == null) { - throw new IncorrectQueryException("Select arguments are incorrect"); - } - } - } - - protected List doSelect(List sourceElements, QueryContext queryContext) throws IncorrectQueryException { - List> selectArguments = queryContext.getSelectArguments(); - List> notAggregateArgs = selectArguments.stream(). - filter(a -> !a.isAggregate()). - collect(Collectors.toList()); - List> aggregateArgs = selectArguments.stream(). - filter(a -> a.isAggregate()). - collect(Collectors.toList()); - - // Step#1: calculate value for each select argument - calculateAggregateArguments(sourceElements, aggregateArgs); - calculateNotAggregateArguments(sourceElements, notAggregateArgs); - - // Step#2: create result class instances by using calculated - // in step#1 values of select arguments - Class resultClass = queryContext.getResultClass(); - Class[] constructorArgTypes = getConstructorParameterTypes(selectArguments); - try { - Constructor resultClassConstructor = resultClass.getDeclaredConstructor(constructorArgTypes); - List results = null; - if (!notAggregateArgs.isEmpty() && aggregateArgs.isEmpty()) { - // simple select without aggregations and grouping - // just calculate all select arguments for each source element - results = calculateResult(sourceElements, resultClassConstructor, notAggregateArgs); - } - if (notAggregateArgs.isEmpty() && !aggregateArgs.isEmpty()) { - // exceptional case when all select arguments are aggregate functions - // and no any grouping, so result will be just one row - R result = calculateOnlyAggregatedResult(resultClassConstructor, aggregateArgs); - results = Collections.singletonList(result); - } else if (!notAggregateArgs.isEmpty() && !aggregateArgs.isEmpty()) { - // case when aggregate function in arguments exist - // and not-aggregate also - suppose that they are grouping arguments - // suppose that source elements belong to only one group - // thus we can calculate all results and get first row, because - // the other will be the same - R result = calculateMixedResult(sourceElements.get(0), resultClassConstructor, selectArguments); - results = Collections.singletonList(result); - } - return results; - } catch (NoSuchMethodException e) { - throw new IncorrectQueryException("Constructor of result class = " + resultClass - + " with arg types = " + Arrays.toString(constructorArgTypes) - + " not found"); - } - } - - protected void calculateNotAggregateArguments(List sourceElements, List> selectArguments) { - for (SelectArgument selectArgument : selectArguments) { - // apply function for each element of source and store to map [element <-> value] - Map elementValues = new HashMap<>(sourceElements.size()); - for (S element : sourceElements) { - Object value = selectArgument.getFunction().apply(element); - elementValues.put(element, value); - if (selectArgument.getValueClazz() == null) { - selectArgument.setValueClazz(value.getClass()); - } - } - selectArgument.setValues(elementValues); - } - } - - protected void calculateAggregateArguments(List sourceElements, List> selectArguments) { - for (SelectArgument selectArgument : selectArguments) { - AggregateFunction aggregateFunction = selectArgument.getAggregateFunction(); - Object aggregateValue = aggregateFunction.apply(sourceElements); - selectArgument.setAggregateValue(aggregateValue); - selectArgument.setValueClazz(aggregateValue.getClass()); - } - } - - protected List calculateResult(List sourceElements, Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { - try { - List results = new ArrayList<>(sourceElements.size()); - for (S sourceElement : sourceElements) { - R resultElement = convertToResultObject(resultClassConstructor, sourceElement, selectArguments); - results.add(resultElement); - } - return results; - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); - } - } - - protected R calculateOnlyAggregatedResult(Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { - try { - return convertToResultObject(resultClassConstructor, null, selectArguments); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); - } - } - - protected R calculateMixedResult(S sourceElement, Constructor resultClassConstructor, List> selectArguments) throws IncorrectQueryException { - try { - return convertToResultObject(resultClassConstructor, sourceElement, selectArguments); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new IncorrectQueryException("Cannot instantiate result class instance: " + e.getMessage()); - } - } - - protected static Class[] getConstructorParameterTypes(List> arguments) { - Class[] types = new Class[arguments.size()]; - // arguments are supposed to be sorted by order - for (int i = 0; i < arguments.size(); i++) { - types[i] = arguments.get(i).getValueClazz(); - } - return types; - } - - protected static R convertToResultObject(Constructor resultConstructor, S source, List> selectArguments) - throws IllegalAccessException, InvocationTargetException, InstantiationException { - Object[] constructorArguments = new Object[selectArguments.size()]; - for (int i = 0; i < selectArguments.size(); i++) { - SelectArgument selectArgument = selectArguments.get(i); - Object value = (selectArgument.isAggregate()) - ? selectArgument.getAggregatedValue() - : selectArgument.getValues().get(source); - constructorArguments[i] = value; - } - return resultConstructor.newInstance(constructorArguments); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java deleted file mode 100644 index e55bc3f..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/DistinctOperation.java +++ /dev/null @@ -1,32 +0,0 @@ -package library.core.operations.impl; - -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; -import library.core.QueryContext; - -import java.util.*; - -public final class DistinctOperation implements QueryOperation { - - @Override - public OperationType getType() { - return OperationType.DISTINCT_OP; - } - - @Override - public void execute(QueryContext queryContext) { - // filter duplicates - List result = queryContext.getResult(); - // iterate by list of results and remove duplicated elements - // HashSet used because it can contain the only unique elements - Set distinctElements = new HashSet<>(result.size()); - for (Iterator iterator = result.iterator(); iterator.hasNext();) { - R element = iterator.next(); - if (!distinctElements.contains(element)) { - distinctElements.add(element); - } else { - iterator.remove(); - } - } - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java deleted file mode 100644 index 8645d3f..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/GroupingSelectOperation.java +++ /dev/null @@ -1,110 +0,0 @@ -package library.core.operations.impl; - -import library.core.exceptions.IncorrectQueryException; -import library.core.model.GroupingCondition; -import library.core.model.SelectArgument; -import library.core.operations.OperationType; -import library.core.QueryContext; - -import java.util.*; - -/** - * This type of operation used when select query is grouping. - * Some additional preparations are required before do select - * for each group of elements. - */ -public final class GroupingSelectOperation extends AbstractSelectOperation { - - @Override - public OperationType getType() { - return OperationType.GROUPING_SELECT_OP; - } - - @Override - public void validate(QueryContext queryContext) throws IncorrectQueryException { - super.validate(queryContext); - // check that select arguments consist of aggregate functions or grouping conditions only - List> selectArguments = queryContext.getSelectArguments(); - List> groupingConditions = queryContext.getGroupingConditions(); - long aggregateFunctionsCnt = selectArguments.stream().filter(SelectArgument::isAggregate).count(); - long simpleFunctionsCnt = selectArguments.size() - aggregateFunctionsCnt; - if (simpleFunctionsCnt != groupingConditions.size()) { - throw new IncorrectQueryException("The only grouping expressions or aggregate functions " - + "are permitted in grouping select query."); - } - } - - @Override - public void execute(QueryContext queryContext) throws IncorrectQueryException { - List sourceElements = queryContext.getSource(); - // in case when all rows have been filtered out - if (sourceElements.isEmpty()) { - return; - } - - // Step#1: calculate grouping value for each source element - List> groupingConditions = queryContext.getGroupingConditions(); - calculateGroupingConditionValues(sourceElements, groupingConditions); - - // Step#2: grouping source elements - Map> groupsOfElements = groupElementsByConditions(sourceElements, groupingConditions); - - // Step#3: calculate select argument for each group of elements separately - for (String groupKey : groupsOfElements.keySet()) { - List groupElements = groupsOfElements.get(groupKey); - List groupResults = doSelect(groupElements, queryContext); - queryContext.addResult(groupResults); - } - } - - private Map> groupElementsByConditions(List sourceElements, List> conditions) { - // for each source element the groupKey is calculated - Map> groups = new HashMap<>(); - for (S element : sourceElements) { - String groupKey = calculateGroupKeyOfElement(element, conditions); - List groupElements = groups.get(groupKey); - if (groupElements == null) { - groupElements = new ArrayList<>(); - groups.put(groupKey, groupElements); - } - groupElements.add(element); - } - return groups; - } - - /* - * GroupKey consists of hashcodes of condition values for this element - * like "84141-14515-6111" in case of 3 grouping conditions and - * hashcode(condition_1_value) = 84141, hashcode(condition_2_value) = 14515, hashcode(condition_3_value) = 6111 - * elements with same groupKey belongs to the same group - * - * @param element source element for which groupKey has to be calculated - * @param conditions list of groupBy conditions - * @param source element type - * @return calculated GroupKey for this element - */ - private static String calculateGroupKeyOfElement(S element, List> conditions) { - StringBuilder groupKeyBuilder = new StringBuilder(); - boolean first = true; - for (GroupingCondition condition : conditions) { - if (!first) groupKeyBuilder.append("-"); - else first = false; - - Map values = condition.getGroupedValues(); - Object elValue = values.get(element); - groupKeyBuilder.append(elValue.hashCode()); - } - return groupKeyBuilder.toString(); - } - - private void calculateGroupingConditionValues(List sourceElements, List> groupingConditions) { - for (GroupingCondition condition : groupingConditions) { - Map elementValues = new HashMap<>(sourceElements.size()); - for (S element : sourceElements) { - Object groupedValue = condition.getFunction().apply(element); - elementValues.put(element, groupedValue); - } - condition.setGroupedValues(elementValues); - } - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java deleted file mode 100644 index 43d6e7b..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/HavingOperation.java +++ /dev/null @@ -1,28 +0,0 @@ -package library.core.operations.impl; - -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; -import library.core.QueryContext; - -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public class HavingOperation implements QueryOperation { - - @Override - public final OperationType getType() { - return OperationType.HAVING_OP; - } - - @Override - public final void execute(QueryContext queryContext) { - // filter result list by using having predicate - Predicate havingCondition = queryContext.getHaving(); - List filteredResult = queryContext.getResult().stream(). - filter(havingCondition). - collect(Collectors.toList()); - // set filtered result - queryContext.setResult(filteredResult); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java deleted file mode 100644 index 0cb7b9e..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/LimitOperation.java +++ /dev/null @@ -1,26 +0,0 @@ -package library.core.operations.impl; - -import library.core.QueryContext; -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; - -import java.util.List; -import java.util.stream.Collectors; - -public class LimitOperation implements QueryOperation { - - @Override - public final OperationType getType() { - return OperationType.LIMIT_OP; - } - - @Override - public final void execute(QueryContext queryContext) { - // limit result list by using stream limit() method - List cutResult = queryContext.getResult().stream(). - limit(queryContext.getLimit()). - collect(Collectors.toList()); - // set cut result list ot context - queryContext.setResult(cutResult); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java deleted file mode 100644 index fb7b5e2..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/OrderByOperation.java +++ /dev/null @@ -1,28 +0,0 @@ -package library.core.operations.impl; - -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; -import library.core.QueryContext; -import org.apache.commons.collections4.comparators.ComparatorChain; - -import java.util.Collections; -import java.util.Comparator; - -public class OrderByOperation implements QueryOperation { - - @Override - public final OperationType getType() { - return OperationType.ORDER_BY_OP; - } - - @Override - public final void execute(QueryContext queryContext) { - // Apache ComparatorChain used to create chain of comparators - // and order by this one - ComparatorChain comparatorChain = new ComparatorChain<>(); - for (Comparator orderByComparator : queryContext.getOrderBy()) { - comparatorChain.addComparator(orderByComparator); - } - Collections.sort(queryContext.getResult(), comparatorChain); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java deleted file mode 100644 index 1304271..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/SimpleSelectOperation.java +++ /dev/null @@ -1,45 +0,0 @@ -package library.core.operations.impl; - -import library.core.exceptions.IncorrectQueryException; -import library.core.model.SelectArgument; -import library.core.operations.OperationType; -import library.core.QueryContext; - -import java.util.List; - -/** - * This type of operation used when select query is not grouping. - */ -public class SimpleSelectOperation extends AbstractSelectOperation { - - @Override - public final OperationType getType() { - return OperationType.SIMPLE_SELECT_OP; - } - - @Override - public final void validate(QueryContext queryContext) throws IncorrectQueryException { - super.validate(queryContext); - // check that there is not aggregate functions at all in "select" statement - // or if exists, then all arguments must be aggregate functions - // because this type of query doesn't have GroupBy condition and - // simple expressions are not permitted in "select" statement - List> selectArguments = queryContext.getSelectArguments(); - long aggregateArgsCnt = selectArguments.stream().filter(SelectArgument::isAggregate).count(); - if (aggregateArgsCnt != 0 && aggregateArgsCnt != selectArguments.size()) { - throw new IncorrectQueryException("The only grouping expressions or aggregate functions " - + "are permitted in select query with aggregate functions."); - } - } - - @Override - public final void execute(QueryContext queryContext) throws IncorrectQueryException { - List sourceElements = queryContext.getSource(); - // in case when all rows have been filtered out - if (sourceElements.isEmpty()) { - return; - } - List results = doSelect(sourceElements, queryContext); - queryContext.addResult(results); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java deleted file mode 100644 index 8932485..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/UnionOperation.java +++ /dev/null @@ -1,29 +0,0 @@ -package library.core.operations.impl; - -import library.api.Query; -import library.core.operations.OperationType; -import library.core.QueryContext; -import library.core.exceptions.IncorrectQueryException; -import library.core.operations.QueryOperation; - -import java.util.LinkedList; -import java.util.List; - -public final class UnionOperation implements QueryOperation { - - @Override - public OperationType getType() { - return OperationType.UNION_OP; - } - - @Override - public void execute(QueryContext queryContext) throws IncorrectQueryException { - for (Query unionQuery : queryContext.getUnions()) { - // execute union query, get its result list and put it into linked list - List unionQueryResult = new LinkedList<>(); - unionQuery.execute().forEach(unionQueryResult::add); - // after that this result is "glued" to our current result - queryContext.addResult(unionQueryResult); - } - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java deleted file mode 100644 index 92bb803..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/operations/impl/WhereOperation.java +++ /dev/null @@ -1,28 +0,0 @@ -package library.core.operations.impl; - -import library.core.operations.OperationType; -import library.core.operations.QueryOperation; -import library.core.QueryContext; - -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public final class WhereOperation implements QueryOperation { - - @Override - public OperationType getType() { - return OperationType.WHERE_OP; - } - - @Override - public void execute(QueryContext queryContext) { - Predicate whereCondition = queryContext.getWhere(); - // filter source list by using predicate from "where" statement - List filteredSource = queryContext.getSource().stream(). - filter(whereCondition). - collect(Collectors.toList()); - // set filtered source list to context - queryContext.setSource(filteredSource); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java deleted file mode 100644 index 5932c2a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/main/java/library/core/utils/NumberUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -package library.core.utils; - -import java.util.function.BiFunction; - -/** - * Util class to perform math operations with Number objects. - * - * Important assumption: - * A both arguments are supposed to having the same type, - * e.g. Long and Long, Integer and Integer and so on, - * because the real type is defined by the first argument only. - */ -public class NumberUtils { - - public static final BiFunction SUM_NUMBERS = (n1, n2) -> { - Class numberClazz = n1.getClass(); - if (numberClazz.equals(Integer.class)) { - return n1.intValue() + n2.intValue(); - } - else if (numberClazz.equals(Long.class)) { - return n1.longValue() + n2.longValue(); - } - else if (numberClazz.equals(Double.class)) { - return n1.doubleValue() + n2.doubleValue(); - } - else if (numberClazz.equals(Float.class)) { - return n1.floatValue() + n2.floatValue(); - } - else { - throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); - } - }; - - public static final BiFunction DIV_NUMBERS = (n1, n2) -> { - Class numberClazz = n1.getClass(); - if (numberClazz.equals(Integer.class)) { - return n1.intValue() / n2.intValue(); - } - else if (numberClazz.equals(Long.class)) { - return n1.longValue() / n2.longValue(); - } - else if (numberClazz.equals(Double.class)) { - return n1.doubleValue() / n2.doubleValue(); - } - else if (numberClazz.equals(Float.class)) { - return n1.floatValue() / n2.floatValue(); - } - else { - throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); - } - }; - - public static final BiFunction COMPARE_NUMBERS = (n1, n2) -> { - Class numberClazz = n1.getClass(); - if (numberClazz.equals(Integer.class)) { - return Integer.compare(n1.intValue(), n2.intValue()); - } - else if (numberClazz.equals(Long.class)) { - return Long.compare(n1.longValue(), n2.longValue()); - } - else if (numberClazz.equals(Double.class)) { - return Double.compare(n1.doubleValue(), n2.doubleValue()); - } - else if (numberClazz.equals(Float.class)) { - return Float.compare(n1.floatValue(), n2.floatValue()); - } - else { - throw new IllegalArgumentException("Number class = " + numberClazz + " not supported"); - } - }; -} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java deleted file mode 100644 index 77d6d20..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/CorrectQueryTest.java +++ /dev/null @@ -1,270 +0,0 @@ -package library; - -import client.Statistics; -import client.Student; -import library.api.Conditions; -import library.api.Sources; -import library.core.exceptions.IncorrectQueryException; -import org.junit.Test; - -import java.time.LocalDate; -import java.util.Iterator; - -import static client.Student.student; -import static library.api.Aggregates.*; -import static library.api.Conditions.like; -import static library.api.Conditions.not; -import static library.api.OrderByConditions.asc; -import static library.api.OrderByConditions.desc; -import static library.api.Sources.from; -import static library.api.Sources.list; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Main test class with many test samples. - */ -public class CorrectQueryTest { - - @Test - public void test_TaskSampleQuery() throws IncorrectQueryException { - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) - .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) - .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, constant("all"), count(s -> 1), avg(Student::age)) - ) - .execute(); - - Iterator resultIterator = statistics.iterator(); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("all", 1L, 30L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("494", 2L, 24L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); - assertFalse(resultIterator.hasNext()); - } - - @Test - public void test_SimpleSelectQuery() throws IncorrectQueryException { - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) - .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) - .execute(); - - Iterator resultIterator = statistics.iterator(); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 19L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 29L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); - assertFalse(resultIterator.hasNext()); - } - - @Test - public void test_SimpleSelectWithWhereQuery() throws IncorrectQueryException { - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) - .where(not(Conditions.like(Student::getName, ".*ov"))) - .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) - .execute(); - - Iterator resultIterator = statistics.iterator(); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("495", 1L, 29L), resultIterator.next()); - assertFalse(resultIterator.hasNext()); - } - - @Test - public void test_SimpleSelectWithLimitQuery() throws IncorrectQueryException { - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, s -> 1L, Student::age) - .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) - .limit(2) - .execute(); - - Iterator resultIterator = statistics.iterator(); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 19L), resultIterator.next()); - assertTrue(resultIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 29L), resultIterator.next()); - assertFalse(resultIterator.hasNext()); - } - - @Test - public void test_SelectWithAggregateFunctionsWithoutGroupingQuery() throws IncorrectQueryException { - // find student with min age - Iterable minAge = - 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("1996-08-06"), "494"))) - .select(Statistics.class, constant("min"), constant(1L), min(Student::age)) - .execute(); - - Iterator minAgeIterator = minAge.iterator(); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("min", 1L, 19L), minAgeIterator.next()); - assertFalse(minAgeIterator.hasNext()); - - // find student with max age - Iterable maxAge = - from(list( - student("ivanov", LocalDate.parse("1986-08-06"), "494"), - student("sidorov", LocalDate.parse("1986-08-06"), "495"), - student("smith", LocalDate.parse("1946-08-06"), "495"), - student("petrov", LocalDate.parse("1996-08-06"), "494"))) - .select(Statistics.class, constant("max"), constant(1L), max(Student::age)) - .execute(); - - Iterator maxAgeIterator = maxAge.iterator(); - assertTrue(maxAgeIterator.hasNext()); - assertEquals(new Statistics("max", 1L, 69L), maxAgeIterator.next()); - assertFalse(maxAgeIterator.hasNext()); - - // find student with average age of all students - Iterable avgAge = - from(list( - student("ivanov", LocalDate.parse("1986-08-06"), "494"), - student("sidorov", LocalDate.parse("1986-08-06"), "495"), - student("smith", LocalDate.parse("1946-08-06"), "495"), - student("petrov", LocalDate.parse("1996-08-06"), "494"))) - .select(Statistics.class, constant("average"), constant(1L), avg(Student::age)) - .execute(); - - Iterator avgAgeIterator = avgAge.iterator(); - assertTrue(avgAgeIterator.hasNext()); - assertEquals(new Statistics("average", 1L, 36L), avgAgeIterator.next()); - assertFalse(avgAgeIterator.hasNext()); - - // count all students - Iterable cnt = - from(list( - student("ivanov", LocalDate.parse("1986-08-06"), "494"), - student("sidorov", LocalDate.parse("1986-08-06"), "495"), - student("smith", LocalDate.parse("1946-08-06"), "495"), - student("petrov", LocalDate.parse("1996-08-06"), "494"))) - .select(Statistics.class, constant("all"), count(s -> 1), avg(Student::age)) - .execute(); - - Iterator cntIterator = cnt.iterator(); - assertTrue(cntIterator.hasNext()); - assertEquals(new Statistics("all", 4L, 36L), cntIterator.next()); - assertFalse(cntIterator.hasNext()); - } - - @Test - public void test_SelectWithAggregateFunctionsWithGroupingQuery() throws IncorrectQueryException { - // find student with min age by groups - Iterable minAge = - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(s -> 1), min(Student::age)) - .groupBy(Student::getGroup) - .orderBy(asc(Statistics::getGroup)) - .execute(); - - Iterator minAgeIterator = minAge.iterator(); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("494", 2L, 19L), minAgeIterator.next()); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("495", 2L, 29L), minAgeIterator.next()); - assertFalse(minAgeIterator.hasNext()); - } - - @Test - public void test_SelectWithManyUnionsQuery() throws IncorrectQueryException { - // find student with min age - Iterable minAndMaxAndAvgAge = - 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("1996-08-06"), "494"))) - .select(Statistics.class, constant("min"), constant(1L), min(Student::age)) - .union( - from(list( - student("ivanov", LocalDate.parse("1986-08-06"), "494"), - student("sidorov", LocalDate.parse("1986-08-06"), "495"), - student("smith", LocalDate.parse("1946-08-06"), "495"), - student("petrov", LocalDate.parse("1996-08-06"), "494"))) - .select(Statistics.class, constant("max"), constant(1L), max(Student::age)) - ) - .union( - from(list( - student("ivanov", LocalDate.parse("1986-08-06"), "494"), - student("sidorov", LocalDate.parse("1986-08-06"), "495"), - student("smith", LocalDate.parse("1946-08-06"), "495"), - student("petrov", LocalDate.parse("1996-08-06"), "494"))) - .select(Statistics.class, constant("average"), constant(1L), avg(Student::age)) - ) - .execute(); - - Iterator minAndMaxAndAvgAgeIterator = minAndMaxAndAvgAge.iterator(); - assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); - assertEquals(new Statistics("average", 1L, 36L), minAndMaxAndAvgAgeIterator.next()); - assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); - assertEquals(new Statistics("max", 1L, 69L), minAndMaxAndAvgAgeIterator.next()); - assertTrue(minAndMaxAndAvgAgeIterator.hasNext()); - assertEquals(new Statistics("min", 1L, 19L), minAndMaxAndAvgAgeIterator.next()); - assertFalse(minAndMaxAndAvgAgeIterator.hasNext()); - } - - @Test - public void test_SelectWithAggregateFunctionsWithManyGroupingConditionsQuery() throws IncorrectQueryException { - // group students by group and age and calculate their count - Iterable minAge = - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(s -> 1), Student::age) - .groupBy(Student::getGroup, Student::age) - .orderBy(asc(Statistics::getGroup), asc(Statistics::getAge)) - .execute(); - - Iterator minAgeIterator = minAge.iterator(); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 19L), minAgeIterator.next()); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("494", 1L, 29L), minAgeIterator.next()); - assertTrue(minAgeIterator.hasNext()); - assertEquals(new Statistics("495", 2L, 29L), minAgeIterator.next()); - assertFalse(minAgeIterator.hasNext()); - } -} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java deleted file mode 100644 index e698cec..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/collectionql/src/test/java/library/IncorrectQueryTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package library; - -import client.Statistics; -import client.Student; -import library.api.Conditions; -import library.core.exceptions.IncorrectQueryException; -import org.junit.Test; - -import java.time.LocalDate; - -import static client.Student.student; -import static library.api.Aggregates.avg; -import static library.api.Aggregates.count; -import static library.api.OrderByConditions.asc; -import static library.api.OrderByConditions.desc; -import static library.api.Sources.from; -import static library.api.Sources.list; - -/** - * Test class contains cases with incorrect library usage. - * - * In most such cases library should generate IncorrectQueryException, - * in other cases library generates IllegalArgumentException - * or NullPointerException in case when required argument is null. - */ -public class IncorrectQueryTest { - - @Test(expected = IllegalArgumentException.class) - public void test_EmptySourceQuery() throws IncorrectQueryException { - from(list(/* empty */)) - .select(Statistics.class) - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void test_EmptyListOfSelectArgs() throws IncorrectQueryException { - from(list(new Object())).select(Object.class).execute(); - } - - @Test(expected = NullPointerException.class) - public void test_NullResultClass() throws IncorrectQueryException { - from(list(new Object())).select(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void test_NullWhereStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).where(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void test_NullOrderByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).orderBy(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void test_NullGroupByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).groupBy(null).execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void test_EmptyOrderByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).orderBy().execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void test_EmptyGroupByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).groupBy().execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void test_IncorrectLimitStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).limit(0).execute(); - } - - @Test(expected = IncorrectQueryException.class) - public void test_IncorrectSelectArguments() throws IncorrectQueryException { - // class Statistics doesn't have constructor with 2 arguments - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(Student::getGroup)) - .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) - .groupBy(Student::getGroup) - .having(s -> s.getCount() > 0) - .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) - .limit(100) - .execute(); - } - - @Test(expected = IncorrectQueryException.class) - public void test_AggregateAndNotAggregateFunctions_InNotGroupingQuery() throws IncorrectQueryException { - // select statement contains Student::getGroup but there is no such grouping function - // in such case the only aggregate functions or constant() are permitted - 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("1996-08-06"), "494"))) - .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age)) - .where(Conditions.like(Student::getName, ".*ov").and(s -> s.age() > 10)) - .orderBy(asc(Statistics::getGroup), desc(Statistics::getCount)) - .limit(100) - .execute(); - } -} \ No newline at end of file From c7f1c737d5fb50a11bc1b9f41dcd23854c098d39 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 01:23:36 +0300 Subject: [PATCH 12/17] add threads --- .../liza22/threads/task1/Counter.java | 76 ++++++++++++ .../liza22/threads/task2/RollCall.java | 87 ++++++++++++++ .../liza22/threads/task3/BlockingQueue.java | 75 ++++++++++++ .../threads/task3/BlockingQueueMain.java | 112 ++++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java new file mode 100644 index 0000000..7771d90 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java @@ -0,0 +1,76 @@ +package task1; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + + +public class Counter { + + private static final int DELAY_BETWEEN_COUNTER_SECONDS = 1; + + private static final int DEFAULT_COUNT_OF_THREADS = 5; + + public static void main(String[] args) throws InterruptedException { + final int countOfThreads = (args.length == 0) ? DEFAULT_COUNT_OF_THREADS : Integer.parseInt(args[0]); + if (countOfThreads <= 1) { + throw new IllegalArgumentException("Count of threads must be > 1"); + } + + + ExecutorService executorService = Executors.newFixedThreadPool(countOfThreads); + final CountDownLatch initTracker = new CountDownLatch(countOfThreads); + final ReentrantLock lock = new ReentrantLock(); + + + Map conditions = new HashMap<>(countOfThreads); + for (int i = 1; i <= countOfThreads; i++) { + Condition iCondition = lock.newCondition(); + conditions.put(i, iCondition); + } + + + for (int i = 1; i <= countOfThreads; i++) { + + final int threadNum = i; + + final Condition myCondition = conditions.get(i); + + final Condition nextCondition = (i == countOfThreads) ? conditions.get(1) : conditions.get(i+1); + executorService.execute(new Runnable() { + @Override + public void run() { + lock.lock(); + try { + + initTracker.countDown(); + while (true) { + + myCondition.await(); + System.out.println("Thread-" + threadNum); + TimeUnit.SECONDS.sleep(DELAY_BETWEEN_COUNTER_SECONDS); + + nextCondition.signal(); + } + } catch (InterruptedException e) { + // finish loop + } finally { + lock.unlock(); + } + } + }); + } + + + initTracker.await(); + try { + lock.lock(); + + conditions.get(1).signal(); + } finally { + lock.unlock(); + } + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java new file mode 100644 index 0000000..f6938fe --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java @@ -0,0 +1,87 @@ +package task2; + +import java.util.concurrent.*; + +public class RollCall { + + private static final int DELAY_BETWEEN_CALL_SECONDS = 1; + + private static final int DEFAULT_COUNT_OF_THREADS = 10; + + private static int tries; + + public static void main(String[] args) throws InterruptedException { + final int countOfThreads = (args.length == 0) ? DEFAULT_COUNT_OF_THREADS : Integer.parseInt(args[0]); + if (countOfThreads <= 1) { + throw new IllegalArgumentException("Count of threads must be > 1"); + } + + + while (true) { + tries++; + + ExecutorService executorService = Executors.newFixedThreadPool(countOfThreads); + + + final CountDownLatch initTracker = new CountDownLatch(countOfThreads); + + final CyclicBarrier readyBarrier = new CyclicBarrier(countOfThreads, new Runnable() { + @Override + public void run() { + System.out.println("All ready with " + tries + " tries!"); + System.exit(1); + } + }); + + try { + System.out.println("\nAre you ready?"); + for (int i = 0; i < countOfThreads; i++) { + final int currentNum = i; + + executorService.execute(new Runnable() { + @Override + public void run() { + boolean yes = isReady(); + if (yes) { + System.out.println("Thread#" + (currentNum + 1) + ": Yes"); + + initTracker.countDown(); + try { + + readyBarrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + // ignore exception + } + } else { + + System.out.println("Thread#" + (currentNum+1) + ": No"); + + initTracker.countDown(); + } + } + }); + } + + + initTracker.await(); + + TimeUnit.SECONDS.sleep(DELAY_BETWEEN_CALL_SECONDS); + + } finally { + + readyBarrier.reset(); + executorService.shutdown(); + } + } + } + + /** + * @return true = 90% false = 10% + */ + private static boolean isReady() { + int num = (int) (Math.random() * 10); + int anotherNum = (int) (Math.random() * 10); + return num != anotherNum; + } +} + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java new file mode 100644 index 0000000..71c44a4 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java @@ -0,0 +1,75 @@ +package task3; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class BlockingQueue { + private int maxElements; + + private List queue; + + private ReentrantLock lock = new ReentrantLock(); + private Condition notFull = lock.newCondition(); + private Condition notEmpty = lock.newCondition(); + + public BlockingQueue(int max) { + if (maxElements <= 0) { + throw new IllegalArgumentException("maxElements must be positive"); + } + this.maxElements = max; + queue = new LinkedList<>(); + } + + + public void offer(List elements) { + lock.lock(); + try { + while (!checkEmptyEnough(elements.size())) { + notFull.await(); + } + + queue.addAll(elements); + } catch (InterruptedException e) { + // ignore + } finally { + + notEmpty.signal(); + + lock.unlock(); + } + } + + + private boolean checkEmptyEnough(int requiredSize) { + return (queue.size() + requiredSize) <= maxElements; + } + + + public List take(int countOfElements) { + lock.lock(); + try { + while(!checkFullEnough(countOfElements)) { + notEmpty.await(); + } + int lastElementIndex = queue.size(); + int firstElementIndex = lastElementIndex - countOfElements; + List result = new LinkedList<>(queue.subList(firstElementIndex, lastElementIndex)); + queue.removeAll(result); + return result; + } catch (InterruptedException e) { + // ignore + return Collections.emptyList(); + } finally { + + notFull.signal(); + lock.unlock(); + } + } + + private boolean checkFullEnough(int countOfElements) { + return queue.size() >= countOfElements; + } +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java new file mode 100644 index 0000000..9f6d122 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java @@ -0,0 +1,112 @@ +package task3; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class BlockingQueueMain { + public static void main(String[] args) throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(2); + + try { + System.out.println("\nFirst case - consumer blocked while provider will offer enough elements to queue"); + final BlockingQueue blockingQueue1 = new BlockingQueue<>(5); + final CountDownLatch firstCaseInitTracker = new CountDownLatch(2); + executorService.execute(new Runnable() { + @Override + public void run() { + System.out.println("CONSUMER: try to take 5 elements from queue..."); + List elements = blockingQueue1.take(5); + System.out.println("CONSUMER: elements taken: " + elements); + firstCaseInitTracker.countDown(); + } + }); + executorService.execute(new Runnable() { + @Override + public void run() { + try { + System.out.println("PROVIDER: sleep 3 seconds before offering elements to queue..."); + TimeUnit.SECONDS.sleep(3); + System.out.println("PROVIDER: offer 5 elements to queue..."); + blockingQueue1.offer(Arrays.asList(1, 2, 3, 4, 5)); + firstCaseInitTracker.countDown(); + } catch (InterruptedException e) { + // ignore + } + } + }); + firstCaseInitTracker.await(); + + System.out.println("\nSecond case - provider blocked while consumer will take extra elements from queue"); + final BlockingQueue blockingQueue2 = new BlockingQueue<>(5); + final CountDownLatch secondCaseInitTracker = new CountDownLatch(2); + executorService.execute(new Runnable() { + @Override + public void run() { + System.out.println("PROVIDER: offer 1-5 elements to queue..."); + blockingQueue2.offer(Arrays.asList(1, 2, 3, 4, 5)); + System.out.println("PROVIDER: 1-5 element offered!"); + System.out.println("PROVIDER: offer 5-10 elements to queue..."); + blockingQueue2.offer(Arrays.asList(6, 7, 8, 9, 10)); + System.out.println("PROVIDER: 5-10 element offered!"); + secondCaseInitTracker.countDown(); + } + }); + executorService.execute(new Runnable() { + @Override + public void run() { + System.out.println("CONSUMER: sleep 3 seconds before take elements from queue..."); + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + // ignore + } + System.out.println("CONSUMER: take 5 elements from queue..."); + System.out.println("CONSUMER: Taken elements: " + blockingQueue2.take(5)); + secondCaseInitTracker.countDown(); + } + }); + secondCaseInitTracker.await(); + + System.out.println("\nThird case - provider blocked while consumer will take extra elements from queue one by one"); + final BlockingQueue blockingQueue3 = new BlockingQueue<>(3); + final CountDownLatch thirdCaseInitTracker = new CountDownLatch(2); + executorService.execute(new Runnable() { + @Override + public void run() { + System.out.println("PROVIDER: offer 10 elements to queue one by one..."); + for (int i = 1; i <= 10; i++) { + System.out.println("PROVIDER: offer [" + i + "] element to queue..."); + blockingQueue3.offer(Collections.singletonList(i)); + } + System.out.println("PROVIDER: all 10 elements offered to queue!"); + thirdCaseInitTracker.countDown(); + } + }); + executorService.execute(new Runnable() { + @Override + public void run() { + System.out.println("CONSUMER: take 10 elements from queue one by one..."); + for (int i = 1; i <= 10; i++) { + System.out.println("CONSUMER: taken " + blockingQueue3.take(1) + " element from queue..."); + // sleep 1 second before next taking... + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + // ignore + } + } + System.out.println("CONSUMER: all 10 elements are taken from queue!"); + thirdCaseInitTracker.countDown(); + } + }); + thirdCaseInitTracker.await(); + } finally { + executorService.shutdown(); + } + } +} From 9230007bb81a95327e17db553c3258a4824c648e Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 01:52:15 +0300 Subject: [PATCH 13/17] delete task2 --- .../liza22/threads/task2/RollCall.java | 87 ------------------- 1 file changed, 87 deletions(-) delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java deleted file mode 100644 index f6938fe..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java +++ /dev/null @@ -1,87 +0,0 @@ -package task2; - -import java.util.concurrent.*; - -public class RollCall { - - private static final int DELAY_BETWEEN_CALL_SECONDS = 1; - - private static final int DEFAULT_COUNT_OF_THREADS = 10; - - private static int tries; - - public static void main(String[] args) throws InterruptedException { - final int countOfThreads = (args.length == 0) ? DEFAULT_COUNT_OF_THREADS : Integer.parseInt(args[0]); - if (countOfThreads <= 1) { - throw new IllegalArgumentException("Count of threads must be > 1"); - } - - - while (true) { - tries++; - - ExecutorService executorService = Executors.newFixedThreadPool(countOfThreads); - - - final CountDownLatch initTracker = new CountDownLatch(countOfThreads); - - final CyclicBarrier readyBarrier = new CyclicBarrier(countOfThreads, new Runnable() { - @Override - public void run() { - System.out.println("All ready with " + tries + " tries!"); - System.exit(1); - } - }); - - try { - System.out.println("\nAre you ready?"); - for (int i = 0; i < countOfThreads; i++) { - final int currentNum = i; - - executorService.execute(new Runnable() { - @Override - public void run() { - boolean yes = isReady(); - if (yes) { - System.out.println("Thread#" + (currentNum + 1) + ": Yes"); - - initTracker.countDown(); - try { - - readyBarrier.await(); - } catch (InterruptedException | BrokenBarrierException e) { - // ignore exception - } - } else { - - System.out.println("Thread#" + (currentNum+1) + ": No"); - - initTracker.countDown(); - } - } - }); - } - - - initTracker.await(); - - TimeUnit.SECONDS.sleep(DELAY_BETWEEN_CALL_SECONDS); - - } finally { - - readyBarrier.reset(); - executorService.shutdown(); - } - } - } - - /** - * @return true = 90% false = 10% - */ - private static boolean isReady() { - int num = (int) (Math.random() * 10); - int anotherNum = (int) (Math.random() * 10); - return num != anotherNum; - } -} - From cb9015316a9973ea6c3bfbca01aaf5fdb5250407 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 02:11:33 +0300 Subject: [PATCH 14/17] checkstyle fixed --- .../liza22/threads/task1/Counter.java | 18 ++++++++++--- .../liza22/threads/task3/BlockingQueue.java | 6 ++--- .../threads/task3/BlockingQueueMain.java | 27 ++++++++++++++----- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java index 7771d90..a86e3e1 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java @@ -1,4 +1,4 @@ -package task1; +package threads.task1; import java.util.HashMap; import java.util.Map; @@ -14,7 +14,12 @@ public class Counter { private static final int DEFAULT_COUNT_OF_THREADS = 5; public static void main(String[] args) throws InterruptedException { - final int countOfThreads = (args.length == 0) ? DEFAULT_COUNT_OF_THREADS : Integer.parseInt(args[0]); + final int countOfThreads; + if (args.length == 0) { + countOfThreads = DEFAULT_COUNT_OF_THREADS + } else { + countOfThreads = Integer.parseInt(args[0]); + } if (countOfThreads <= 1) { throw new IllegalArgumentException("Count of threads must be > 1"); } @@ -38,7 +43,12 @@ public static void main(String[] args) throws InterruptedException { final Condition myCondition = conditions.get(i); - final Condition nextCondition = (i == countOfThreads) ? conditions.get(1) : conditions.get(i+1); + final Condition nextCondition; + if (i == countOfThreads) { + nextCondition = conditions.get(1) + } else { + nextCondition = conditions.get(i + 1); + } executorService.execute(new Runnable() { @Override public void run() { @@ -73,4 +83,4 @@ public void run() { lock.unlock(); } } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java index 71c44a4..10aec29 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueue.java @@ -1,4 +1,4 @@ -package task3; +package threads.task3; import java.util.Collections; import java.util.LinkedList; @@ -6,7 +6,7 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -public class BlockingQueue { +public final class BlockingQueue { private int maxElements; private List queue; @@ -51,7 +51,7 @@ private boolean checkEmptyEnough(int requiredSize) { public List take(int countOfElements) { lock.lock(); try { - while(!checkFullEnough(countOfElements)) { + while (!checkFullEnough(countOfElements)) { notEmpty.await(); } int lastElementIndex = queue.size(); diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java index 9f6d122..6552714 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java @@ -1,4 +1,4 @@ -package task3; +package threads.task3; import java.util.Arrays; import java.util.Collections; @@ -9,6 +9,18 @@ import java.util.concurrent.TimeUnit; public class BlockingQueueMain { + public static final int COUNT = 10; + public static final int N1 = 1; + public static final int N2 = 2; + public static final int N3 = 3; + public static final int N4 = 4; + public static final int N5 = 5; + public static final int N6 = 6; + public static final int N7 = 7; + public static final int N8 = 8; + public static final int N9 = 9; + public static final int N10 = 10; + public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(2); @@ -32,7 +44,7 @@ public void run() { System.out.println("PROVIDER: sleep 3 seconds before offering elements to queue..."); TimeUnit.SECONDS.sleep(3); System.out.println("PROVIDER: offer 5 elements to queue..."); - blockingQueue1.offer(Arrays.asList(1, 2, 3, 4, 5)); + blockingQueue1.offer(Arrays.asList(N1, N2, N3, N4, N5)); firstCaseInitTracker.countDown(); } catch (InterruptedException e) { // ignore @@ -48,10 +60,10 @@ public void run() { @Override public void run() { System.out.println("PROVIDER: offer 1-5 elements to queue..."); - blockingQueue2.offer(Arrays.asList(1, 2, 3, 4, 5)); + blockingQueue2.offer(Arrays.asList(N1, N2, N3, N4, N5)); System.out.println("PROVIDER: 1-5 element offered!"); System.out.println("PROVIDER: offer 5-10 elements to queue..."); - blockingQueue2.offer(Arrays.asList(6, 7, 8, 9, 10)); + blockingQueue2.offer(Arrays.asList(N6, N7, N8, N9, N10)); System.out.println("PROVIDER: 5-10 element offered!"); secondCaseInitTracker.countDown(); } @@ -72,14 +84,15 @@ public void run() { }); secondCaseInitTracker.await(); - System.out.println("\nThird case - provider blocked while consumer will take extra elements from queue one by one"); + System.out.println("\nThird case - " + + "provider blocked while consumer will take extra elements from queue one by one"); final BlockingQueue blockingQueue3 = new BlockingQueue<>(3); final CountDownLatch thirdCaseInitTracker = new CountDownLatch(2); executorService.execute(new Runnable() { @Override public void run() { System.out.println("PROVIDER: offer 10 elements to queue one by one..."); - for (int i = 1; i <= 10; i++) { + for (int i = 1; i <= COUNT; i++) { System.out.println("PROVIDER: offer [" + i + "] element to queue..."); blockingQueue3.offer(Collections.singletonList(i)); } @@ -91,7 +104,7 @@ public void run() { @Override public void run() { System.out.println("CONSUMER: take 10 elements from queue one by one..."); - for (int i = 1; i <= 10; i++) { + for (int i = 1; i <= COUNT; i++) { System.out.println("CONSUMER: taken " + blockingQueue3.take(1) + " element from queue..."); // sleep 1 second before next taking... try { From 169ceef03c72c51551faaffd9819f1d78ba3faec Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 02:17:56 +0300 Subject: [PATCH 15/17] checkstyle fixed --- .../liza22/threads/task3/BlockingQueueMain.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java index 6552714..0179b62 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task3/BlockingQueueMain.java @@ -32,7 +32,7 @@ public static void main(String[] args) throws InterruptedException { @Override public void run() { System.out.println("CONSUMER: try to take 5 elements from queue..."); - List elements = blockingQueue1.take(5); + List elements = blockingQueue1.take(N5); System.out.println("CONSUMER: elements taken: " + elements); firstCaseInitTracker.countDown(); } @@ -42,7 +42,7 @@ public void run() { public void run() { try { System.out.println("PROVIDER: sleep 3 seconds before offering elements to queue..."); - TimeUnit.SECONDS.sleep(3); + TimeUnit.SECONDS.sleep(N3); System.out.println("PROVIDER: offer 5 elements to queue..."); blockingQueue1.offer(Arrays.asList(N1, N2, N3, N4, N5)); firstCaseInitTracker.countDown(); @@ -73,19 +73,19 @@ public void run() { public void run() { System.out.println("CONSUMER: sleep 3 seconds before take elements from queue..."); try { - TimeUnit.SECONDS.sleep(3); + TimeUnit.SECONDS.sleep(N3); } catch (InterruptedException e) { // ignore } System.out.println("CONSUMER: take 5 elements from queue..."); - System.out.println("CONSUMER: Taken elements: " + blockingQueue2.take(5)); + System.out.println("CONSUMER: Taken elements: " + blockingQueue2.take(N5)); secondCaseInitTracker.countDown(); } }); secondCaseInitTracker.await(); - System.out.println("\nThird case - " + - "provider blocked while consumer will take extra elements from queue one by one"); + System.out.println("\nThird case - " + + "provider blocked while consumer will take extra elements from queue one by one"); final BlockingQueue blockingQueue3 = new BlockingQueue<>(3); final CountDownLatch thirdCaseInitTracker = new CountDownLatch(2); executorService.execute(new Runnable() { From 092d5a3cf15fe0b3b01a616739dc2b15a4f3f712 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 02:25:47 +0300 Subject: [PATCH 16/17] add task2 --- .../liza22/threads/task1/Counter.java | 4 +- .../liza22/threads/task2/RollCall.java | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java index a86e3e1..f1ab341 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task1/Counter.java @@ -16,7 +16,7 @@ public class Counter { public static void main(String[] args) throws InterruptedException { final int countOfThreads; if (args.length == 0) { - countOfThreads = DEFAULT_COUNT_OF_THREADS + countOfThreads = DEFAULT_COUNT_OF_THREADS; } else { countOfThreads = Integer.parseInt(args[0]); } @@ -45,7 +45,7 @@ public static void main(String[] args) throws InterruptedException { final Condition nextCondition; if (i == countOfThreads) { - nextCondition = conditions.get(1) + nextCondition = conditions.get(1); } else { nextCondition = conditions.get(i + 1); } diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java new file mode 100644 index 0000000..6616f4a --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java @@ -0,0 +1,82 @@ +package threads.task2; + +import java.util.concurrent.*; + +public class RollCall { + + private static final int DELAY_BETWEEN_CALL_SECONDS = 1; + + private static final int DEFAULT_COUNT_OF_THREADS = 10; + + private static final int CONST10 = 10; + + private static int tries; + + public static void main(String[] args) throws InterruptedException { + final int countOfThreads; + if (args.length == 0) { + countOfThreads = DEFAULT_COUNT_OF_THREADS; + } else { + countOfThreads = Integer.parseInt(args[0]); + } + if (countOfThreads <= 1) { + throw new IllegalArgumentException("Count of threads must be > 1"); + } + + while (true) { + tries++; + ExecutorService executorService = Executors.newFixedThreadPool(countOfThreads); + + final CountDownLatch initTracker = new CountDownLatch(countOfThreads); + final CyclicBarrier readyBarrier = new CyclicBarrier(countOfThreads, new Runnable() { + @Override + public void run() { + System.out.println("All ready with " + tries + " tries!"); + System.exit(1); + } + }); + + try { + System.out.println("\nAre you ready?"); + for (int i = 0; i < countOfThreads; i++) { + final int currentNum = i; + + executorService.execute(new Runnable() { + @Override + public void run() { + boolean yes = isReady(); + if (yes) { + System.out.println("Thread#" + (currentNum + 1) + ": Yes"); + initTracker.countDown(); + try { + readyBarrier.await(); + } catch (InterruptedException | BrokenBarrierException e) { + // ignore exception + } + } else { + System.out.println("Thread#" + (currentNum+1) + ": No"); + initTracker.countDown(); + } + } + }); + } + + initTracker.await(); + // continue with a small pause + TimeUnit.SECONDS.sleep(DELAY_BETWEEN_CALL_SECONDS); + } finally { + readyBarrier.reset(); + executorService.shutdown(); + } + } + } + + /** + * @return true - 90% false - 10% + */ + private static boolean isReady() { + int num = (int) (Math.random() * CONST10); + int anotherNum = (int) (Math.random() * CONST10); + return num != anotherNum; + } +} From c51f7eaff14fd1c6f64444e83a8dde7c15674574 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 02:28:31 +0300 Subject: [PATCH 17/17] checkstyle fixed --- .../ru/mipt/diht/students/liza22/threads/task2/RollCall.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java index 6616f4a..4fd7af6 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/threads/task2/RollCall.java @@ -54,7 +54,7 @@ public void run() { // ignore exception } } else { - System.out.println("Thread#" + (currentNum+1) + ": No"); + System.out.println("Thread#" + (currentNum + 1) + ": No"); initTracker.countDown(); } }