From 6e367b8e30de2ddc1e9e5fcfc4a2c965a3e14e1e Mon Sep 17 00:00:00 2001 From: liza22 Date: Wed, 16 Dec 2015 21:13:18 +0300 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 5d8f8684f3712d306b2ae8610c6daff550d28f90 Mon Sep 17 00:00:00 2001 From: liza22 Date: Fri, 18 Dec 2015 18:23:29 +0300 Subject: [PATCH 11/20] add CollectionQL --- .../test/java/library/IncorrectQueryTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 index e698cec..de55078 100644 --- 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 @@ -26,34 +26,34 @@ public class IncorrectQueryTest { @Test(expected = IllegalArgumentException.class) - public void test_EmptySourceQuery() throws IncorrectQueryException { + public void testEmptySourceQuery() throws IncorrectQueryException { from(list(/* empty */)) .select(Statistics.class) .execute(); } @Test(expected = IllegalArgumentException.class) - public void test_EmptyListOfSelectArgs() throws IncorrectQueryException { + public void testEmptyListOfSelectArgs() throws IncorrectQueryException { from(list(new Object())).select(Object.class).execute(); } @Test(expected = NullPointerException.class) - public void test_NullResultClass() throws IncorrectQueryException { + public void testNullResultClass() throws IncorrectQueryException { from(list(new Object())).select(null).execute(); } @Test(expected = NullPointerException.class) - public void test_NullWhereStatement() throws IncorrectQueryException { + public void testNullWhereStatement() throws IncorrectQueryException { from(list(new Object())).select(Object.class, o -> 1).where(null).execute(); } @Test(expected = NullPointerException.class) - public void test_NullOrderByStatement() throws IncorrectQueryException { + public void testNullOrderByStatement() throws IncorrectQueryException { from(list(new Object())).select(Object.class, o -> 1).orderBy(null).execute(); } @Test(expected = NullPointerException.class) - public void test_NullGroupByStatement() throws IncorrectQueryException { + public void testNullGroupByStatement() throws IncorrectQueryException { from(list(new Object())).select(Object.class, o -> 1).groupBy(null).execute(); } @@ -63,17 +63,17 @@ public void test_EmptyOrderByStatement() throws IncorrectQueryException { } @Test(expected = IllegalArgumentException.class) - public void test_EmptyGroupByStatement() throws IncorrectQueryException { + public void testEmptyGroupByStatement() throws IncorrectQueryException { from(list(new Object())).select(Object.class, o -> 1).groupBy().execute(); } @Test(expected = IllegalArgumentException.class) - public void test_IncorrectLimitStatement() throws IncorrectQueryException { + public void testIncorrectLimitStatement() throws IncorrectQueryException { from(list(new Object())).select(Object.class, o -> 1).limit(0).execute(); } @Test(expected = IncorrectQueryException.class) - public void test_IncorrectSelectArguments() throws IncorrectQueryException { + public void testIncorrectSelectArguments() throws IncorrectQueryException { // class Statistics doesn't have constructor with 2 arguments Iterable statistics = from(list( @@ -91,7 +91,7 @@ public void test_IncorrectSelectArguments() throws IncorrectQueryException { } @Test(expected = IncorrectQueryException.class) - public void test_AggregateAndNotAggregateFunctions_InNotGroupingQuery() throws IncorrectQueryException { + public void testAggregateAndNotAggregateFunctionsInNotGroupingQuery() 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 a34814c32d13cd120f16a6cc140bbac63d82ee8c Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 13:27:01 +0300 Subject: [PATCH 12/20] add miniORM --- .../mipt/diht/students/liza22/MiniORM/pom.xml | 72 +++++ .../MiniORM/src/checkstyle-suppressions.xml | 9 + .../liza22/MiniORM/src/checkstyle.xml | 175 ++++++++++++ .../src/main/java/mini/orm/api/Column.java | 16 ++ .../java/mini/orm/api/DatabaseService.java | 25 ++ .../main/java/mini/orm/api/PrimaryKey.java | 14 + .../src/main/java/mini/orm/api/Table.java | 16 ++ .../mini/orm/core/JdbcDatabaseService.java | 182 ++++++++++++ .../mini/orm/core/db/ConnectionProvider.java | 12 + .../main/java/mini/orm/core/db/DbConfig.java | 107 +++++++ .../core/db/impl/JdbcConnectionProvider.java | 24 ++ .../mini/orm/core/model/ColumnDescriptor.java | 48 ++++ .../mini/orm/core/model/TableDescriptor.java | 79 +++++ .../java/mini/orm/core/utils/Constants.java | 28 ++ .../java/mini/orm/core/utils/NameUtils.java | 13 + .../mini/orm/core/utils/QueryStorage.java | 72 +++++ .../mini/orm/DatabaseServiceModuleTest.java | 130 +++++++++ .../test/java/mini/orm/model/CarEntity.java | 116 ++++++++ .../IncorrectEntityWithoutColumnAnn.java | 15 + .../IncorrectEntityWithoutPrimaryKeyAnn.java | 14 + .../model/IncorrectEntityWithoutTableAnn.java | 14 + .../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 ------- 59 files changed, 1181 insertions(+), 2074 deletions(-) create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java 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/MiniORM/pom.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml new file mode 100644 index 0000000..877c46d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + mini.orm + orm + 1.0 + + + 1.7 + 1.7 + + + + + com.h2database + h2 + 1.4.190 + + + junit + junit + 4.4 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.16 + + src/checkstyle.xml + src/checkstyle-suppressions.xml + Cp1251 + true + true + + + + validate + validate + + check + + + + + + com.puppycrawl.tools + checkstyle + 6.10.1 + + + + + + + \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml new file mode 100644 index 0000000..ecd3542 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml new file mode 100644 index 0000000..3401cf5 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java new file mode 100644 index 0000000..1dc4837 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java @@ -0,0 +1,16 @@ +package mini.orm.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/* + * Annotation for Table Columns. + * Default value is used now "", but it will be used as "field_name" later in code. + */ +@Target(value = ElementType.FIELD) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface Column { + String name() default ""; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java new file mode 100644 index 0000000..97f581e --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java @@ -0,0 +1,25 @@ +package mini.orm.api; + +import java.util.List; + +/** + * Main ORM interface. + * @param type of entity + * @param type of primary key for entity + */ +public interface DatabaseService { + + T queryById(K entityKey); + + List queryForAll(); + + void insert(T newEntity); + + void update(T updatedEntity); + + void delete(T deleteEntity); + + void createTable(); + + void dropTable(); +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java new file mode 100644 index 0000000..8c2c73d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java @@ -0,0 +1,14 @@ +package mini.orm.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for Column which is Primary Key of table. + */ +@Target(value = ElementType.FIELD) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface PrimaryKey { +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java new file mode 100644 index 0000000..5d0133d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java @@ -0,0 +1,16 @@ +package mini.orm.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for Table. + * Default value is used now "", but it will be used as "class_name" later in code. + */ +@Target(value = ElementType.TYPE) +@Retention(value = RetentionPolicy.RUNTIME) +public @interface Table { + String name() default ""; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java new file mode 100644 index 0000000..75d07e4 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java @@ -0,0 +1,182 @@ +package mini.orm.core; + +import mini.orm.api.DatabaseService; +import mini.orm.core.db.ConnectionProvider; +import mini.orm.core.db.impl.JdbcConnectionProvider; +import mini.orm.core.model.ColumnDescriptor; +import mini.orm.core.model.TableDescriptor; +import mini.orm.core.utils.Constants; +import mini.orm.core.utils.QueryStorage; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * implementation ORM-service by JDBC base. + * @param - content type + * @param - primary key type + */ +public final class JdbcDatabaseService implements DatabaseService { + private static final boolean LOGGING = true; + + private Class entityType; + private TableDescriptor tableDescriptor; + + private ConnectionProvider connectionProvider; + + public JdbcDatabaseService(Class entityClass) { + this.entityType = entityClass; + this.tableDescriptor = TableDescriptor.fromEntityClass(entityClass); + this.connectionProvider = new JdbcConnectionProvider(); + } + + public T queryById(K entityKey) { + // get query with TABLE name and primary key name + String query = QueryStorage.getSelectByPkQuery(tableDescriptor.getTableName(), + tableDescriptor.getPrimaryKey().getColumnName()); + if (LOGGING) { + System.out.println("Method 'queryById' query is: " + query); + } + // make DB connection, then PreparedStatement, run query and processing the ResultSet + try (Connection conn = connectionProvider.getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + stmt.setObject(1, entityKey); + try (ResultSet result = stmt.executeQuery()) { + if (result.next()) { + return buildEntityFromResult(result); + } else { + return null; + } + } + } catch (SQLException e) { + System.err.println("Error while perform queryById: " + e.getMessage()); + return null; + } + } + + public List queryForAll() { + String query = QueryStorage.getSelectAllQuery(tableDescriptor.getTableName()); + if (LOGGING) { + System.out.println("Method 'queryForAll' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet result = stmt.executeQuery(query)) { + List entities = new ArrayList<>(); + while (result.next()) { + entities.add(buildEntityFromResult(result)); + } + return entities; + } catch (SQLException e) { + System.err.println("Error while perform queryForAll: " + e.getMessage()); + return null; + } + } + + public void insert(T newEntity) { + String query = QueryStorage.getInsertQuery(tableDescriptor.getTableName(), tableDescriptor.getColumns().size()); + if (LOGGING) { + System.out.println("Method 'insert' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + for (ColumnDescriptor columnDescriptor : tableDescriptor.getColumns()) { + int bindNum = tableDescriptor.getColumns().indexOf(columnDescriptor) + 1; + Object columnValue = columnDescriptor.getColumnField().get(newEntity); + stmt.setObject(bindNum, columnValue); + } + stmt.executeUpdate(); + } catch (SQLException | IllegalAccessException e) { + System.err.println("Error while perform insert: " + e.getMessage()); + } + } + + public void update(T updatedEntity) { + List updateColumns = tableDescriptor.getColumnsExceptPK(); + String[] updateColumnNames = new String[updateColumns.size()]; + for (ColumnDescriptor cd : updateColumns) { + updateColumnNames[updateColumns.indexOf(cd)] = cd.getColumnName(); + } + String query = QueryStorage.getUpdateByPkQuery(tableDescriptor.getTableName(), + updateColumnNames, tableDescriptor.getPrimaryKey().getColumnName()); + if (LOGGING) { + System.out.println("Method 'update' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + int bindNum = 0; + for (ColumnDescriptor columnDescriptor : updateColumns) { + bindNum = updateColumns.indexOf(columnDescriptor) + 1; + Object columnValue = columnDescriptor.getColumnField().get(updatedEntity); + stmt.setObject(bindNum, columnValue); + } + stmt.setObject(bindNum + 1, tableDescriptor.getPrimaryKey().getColumnField().get(updatedEntity)); + stmt.executeUpdate(); + } catch (SQLException | IllegalAccessException e) { + System.err.println("Error while perform update: " + e.getMessage()); + } + } + + public void delete(T deleteEntity) { + ColumnDescriptor pkColumn = tableDescriptor.getPrimaryKey(); + String query = QueryStorage.getDeleteByPkQuery(tableDescriptor.getTableName(), pkColumn.getColumnName()); + if (LOGGING) { + System.out.println("Method 'delete' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + stmt.setObject(1, pkColumn.getColumnField().get(deleteEntity)); + stmt.executeUpdate(); + } catch (SQLException | IllegalAccessException e) { + System.err.println("Error while perform delete: " + e.getMessage()); + } + } + + public void createTable() { + List columns = tableDescriptor.getColumns(); + String[] columnNames = new String[columns.size()]; + String[] columnTypes = new String[columns.size()]; + for (int i = 0; i < columns.size(); i++) { + ColumnDescriptor columnDescriptor = columns.get(i); + columnNames[i] = columnDescriptor.getColumnName(); + columnTypes[i] = Constants.JAVA_TO_SQL_TYPES.get(columnDescriptor.getColumnType()); + } + String query = QueryStorage.getCreateTableQuery(tableDescriptor.getTableName(), + columnNames, columnTypes, tableDescriptor.getPrimaryKey().getColumnName()); + if (LOGGING) { + System.out.println("Method 'createTable' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); Statement stmt = conn.createStatement()) { + stmt.executeUpdate(query); + } catch (SQLException e) { + System.err.println("Error while perform createTable: " + e.getMessage()); + } + } + + public void dropTable() { + String query = QueryStorage.getDropTableQuery(tableDescriptor.getTableName()); + if (LOGGING) { + System.out.println("Method 'dropTable' query is: " + query); + } + try (Connection conn = connectionProvider.getConnection(); Statement stmt = conn.createStatement()) { + stmt.executeUpdate(query); + } catch (SQLException e) { + System.err.println("Error while perform dropTable: " + e.getMessage()); + } + } + + private T buildEntityFromResult(ResultSet resultSet) { + try { + T entity = entityType.newInstance(); + for (ColumnDescriptor column : tableDescriptor.getColumns()) { + Object columnValue = resultSet.getObject(column.getColumnName()); + column.getColumnField().set(entity, columnValue); + } + return entity; + } catch (Exception e) { + System.err.println("Entity class = " + entityType + " is incorrect: " + e.getMessage()); + return null; + } + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java new file mode 100644 index 0000000..6c72a78 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java @@ -0,0 +1,12 @@ +package mini.orm.core.db; + +import java.sql.Connection; +import java.sql.SQLException; + +/* + * provide Connection to DB. + */ +public interface ConnectionProvider { + + Connection getConnection() throws SQLException; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java new file mode 100644 index 0000000..8da307e --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java @@ -0,0 +1,107 @@ +package mini.orm.core.db; + +import mini.orm.core.utils.Constants; + +import java.io.*; + +/* + * config file with parameters DB connection's. + * will be use by DriverManager to getting DB Connection. + */ +public class DbConfig { + /* + * keys names from property file. + */ + private static final String JDBC_DRIVER_PROP_NAME = "db.jdbc.driver"; + private static final String DB_URL_PROP_NAME = "db.url"; + private static final String DB_USER_PROP_NAME = "db.user"; + private static final String DB_PASSWORD_PROP_NAME = "db.password"; + + private String jdbcDriver; + private String url; + private String username; + private String password; + + public DbConfig() { + init(); + // load Jdbc Driver class + try { + Class.forName(jdbcDriver); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("Driver Class = '" + jdbcDriver + "' not found", e); + } + } + + private void init() { + File cfgFile = new File(Constants.DB_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 DB configuration = '" + line + "'"); + continue; + } + String propName = line.substring(0, indexOfDelimiter); + String propValue = line.substring(indexOfDelimiter + 1, line.length()); + switch (propName) { + case JDBC_DRIVER_PROP_NAME: + jdbcDriver = propValue; + break; + case DB_URL_PROP_NAME: + url = propValue; + break; + case DB_USER_PROP_NAME: + username = propValue; + break; + case DB_PASSWORD_PROP_NAME: + password = propValue; + break; + default: + System.err.println("Property '" + propName + "' not recognized"); + } + } + } catch (FileNotFoundException e) { + System.err.println("DB config file by path = \"" + cfgFile.getAbsolutePath() + "\" not found"); + } catch (IOException e) { + System.err.println("Problem with reading DB config file: " + e.getMessage()); + } + + validate(); + } + + private void validate() { + if (jdbcDriver == null + || url == null + || username == null + || password == null) { + throw new IllegalStateException("DB configuration file is incorrect"); + } + } + + public final String getJdbcDriver() { + return jdbcDriver; + } + + public final String getUrl() { + return url; + } + + public final String getUsername() { + return username; + } + + public final String getPassword() { + return password; + } + + @Override + public final String toString() { + return "DbConfig{" + + "jdbcDriver='" + jdbcDriver + '\'' + + ", url='" + url + '\'' + + ", username='" + username + '\'' + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java new file mode 100644 index 0000000..1c62237 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java @@ -0,0 +1,24 @@ +package mini.orm.core.db.impl; + +import mini.orm.core.db.ConnectionProvider; +import mini.orm.core.db.DbConfig; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * ConnectionProvider on the JDBC base. + * Using DB config with parameters to make Connection. + */ +public class JdbcConnectionProvider implements ConnectionProvider { + private DbConfig dbConfig; + + public JdbcConnectionProvider() { + this.dbConfig = new DbConfig(); + } + + public final Connection getConnection() throws SQLException { + return DriverManager.getConnection(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword()); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java new file mode 100644 index 0000000..bf90929 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java @@ -0,0 +1,48 @@ +package mini.orm.core.model; + +import mini.orm.api.Column; +import mini.orm.core.utils.NameUtils; + +import java.lang.reflect.Field; + +/** + * this class describes one column of table. + */ +public class ColumnDescriptor { + private String name; + private Class type; + private Field columnField; + + ColumnDescriptor(String columnName, Class columnType, Field columnField1) { + this.name = columnName; + this.type = columnType; + this.columnField = columnField1; + columnField.setAccessible(true); + } + + public final String getColumnName() { + return name; + } + + public final Class getColumnType() { + return type; + } + + public final Field getColumnField() { + return columnField; + } + + public static ColumnDescriptor fromEntityField(Field entityField) { + if (!entityField.isAnnotationPresent(Column.class)) { + throw new IllegalArgumentException("Field = " + entityField + " not annotated by @Column"); + } + + String columnName = entityField.getAnnotation(Column.class).name(); + if (columnName.isEmpty()) { + // use default value - field name + columnName = NameUtils.convertFromCamelCaseToUnderscore(entityField.getName()); + } + Class columnType = entityField.getType(); + return new ColumnDescriptor(columnName, columnType, entityField); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java new file mode 100644 index 0000000..1ff1cc5 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java @@ -0,0 +1,79 @@ +package mini.orm.core.model; + +import mini.orm.api.PrimaryKey; +import mini.orm.api.Table; +import mini.orm.core.utils.NameUtils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* + * create descriptor to Table + */ +public final class TableDescriptor { + private String name; + private ColumnDescriptor primaryKey; + private List columns; + + TableDescriptor(String tableName) { + this.name = tableName; + this.columns = new ArrayList<>(); + } + + void addColumn(ColumnDescriptor columnDescriptor) { + columns.add(columnDescriptor); + } + + void setPrimaryKey(ColumnDescriptor primaryKeyColumn) { + this.primaryKey = primaryKeyColumn; + } + + public String getTableName() { + return name; + } + + public List getColumns() { + return Collections.unmodifiableList(columns); + } + + public List getColumnsExceptPK() { + List columnsExceptPK = new ArrayList<>(columns); + columnsExceptPK.remove(primaryKey); + return columnsExceptPK; + } + + public ColumnDescriptor getPrimaryKey() { + return primaryKey; + } + + public static TableDescriptor fromEntityClass(Class entityClass) { + if (!entityClass.isAnnotationPresent(Table.class)) { + throw new IllegalArgumentException("Class = " + entityClass.getSimpleName() + + " is not annotated by @Table"); + } + String tableName = entityClass.getAnnotation(Table.class).name(); + if (tableName.isEmpty()) { + // use default - class name + tableName = NameUtils.convertFromCamelCaseToUnderscore(entityClass.getSimpleName()); + } + + TableDescriptor tableDescriptor = new TableDescriptor(tableName); + boolean primaryKeyExists = false; + for (Field entityField : entityClass.getDeclaredFields()) { + ColumnDescriptor columnDescriptor = ColumnDescriptor.fromEntityField(entityField); + tableDescriptor.addColumn(columnDescriptor); + if (entityField.isAnnotationPresent(PrimaryKey.class)) { + tableDescriptor.setPrimaryKey(columnDescriptor); + primaryKeyExists = true; + } + } + if (!primaryKeyExists) { + throw new IllegalArgumentException("Entity class = " + entityClass.getSimpleName() + + " does not have @PrimaryKey field"); + } + + return tableDescriptor; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java new file mode 100644 index 0000000..9b784cf --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java @@ -0,0 +1,28 @@ +package mini.orm.core.utils; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Project constants. + */ +public class Constants { + public static final String DB_CONFIG_FILE = "db.config"; + + /** + * correlate Java-types with SQL-types. + */ + public static final Map, String> JAVA_TO_SQL_TYPES; + static { + JAVA_TO_SQL_TYPES = new HashMap<>(); + JAVA_TO_SQL_TYPES.put(Boolean.class, "BOOLEAN"); + JAVA_TO_SQL_TYPES.put(boolean.class, "BOOLEAN"); + JAVA_TO_SQL_TYPES.put(Integer.class, "INTEGER"); + JAVA_TO_SQL_TYPES.put(int.class, "INTEGER"); + JAVA_TO_SQL_TYPES.put(Long.class, "BIGINT"); + JAVA_TO_SQL_TYPES.put(long.class, "BIGINT"); + JAVA_TO_SQL_TYPES.put(String.class, "VARCHAR(256)"); + JAVA_TO_SQL_TYPES.put(Date.class, "TIMESTAMP"); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java new file mode 100644 index 0000000..fb0589f --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java @@ -0,0 +1,13 @@ +package mini.orm.core.utils; + +public final class NameUtils { + + /** + * convert CamelCase format string to underscore format using regexp + */ + public static String convertFromCamelCaseToUnderscore(String ccStr) { + String regex = "([a-z])([A-Z])"; + String replacement = "$1_$2"; + return ccStr.replaceAll(regex, replacement).toLowerCase(); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java new file mode 100644 index 0000000..a7a50aa --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java @@ -0,0 +1,72 @@ +package mini.orm.core.utils; + +import java.text.MessageFormat; + +/** + * this class contains SQL queries teplates. + */ +public class QueryStorage { + + private static final String SELECT_BY_PK_QUERY = + "SELECT * FROM {0} WHERE {1} = ?"; + public static String getSelectByPkQuery(String tableName, String pkColumnName) { + return MessageFormat.format(SELECT_BY_PK_QUERY, tableName, pkColumnName); + } + + private static final String SELECT_ALL_QUERY = + "SELECT * FROM {0}"; + public static String getSelectAllQuery(String tableName) { + return MessageFormat.format(SELECT_ALL_QUERY, tableName); + } + + private static final String INSERT_QUERY = + "INSERT INTO {0} VALUES({1})"; + public static String getInsertQuery(String tableName, int countOfColumns) { + StringBuilder valueBinds = new StringBuilder(); + for (int i = 0; i < countOfColumns; i++) { + valueBinds.append("?"); + if (i != countOfColumns - 1) { + valueBinds.append(", "); + } + } + return MessageFormat.format(INSERT_QUERY, tableName, valueBinds); + } + + private static final String UPDATE_BY_PK_QUERY = + "UPDATE {0} SET {1} WHERE {2} = ?"; + public static String getUpdateByPkQuery(String tableName, String[] columns, String pkColumnName) { + StringBuilder valueBinds = new StringBuilder(); + for (int i = 0; i < columns.length; i++) { + valueBinds.append(columns[i]).append("=?"); + if (i != columns.length - 1) { + valueBinds.append(", "); + } + } + return MessageFormat.format(UPDATE_BY_PK_QUERY, tableName, valueBinds, pkColumnName); + } + + private static final String DELETE_BY_PK_QUERY = + "DELETE FROM {0} WHERE {1} = ?"; + public static String getDeleteByPkQuery(String tableName, String pkColumnName) { + return MessageFormat.format(DELETE_BY_PK_QUERY, tableName, pkColumnName); + } + + private static final String CREATE_TABLE_QUERY = + "CREATE TABLE {0} ({1} PRIMARY KEY ( {2} ))"; + public static String getCreateTableQuery(String tableName, String[] columnNames, + String[] columnTypes, String pkColumnName) { + StringBuilder columnsInfo = new StringBuilder(); + for (int i = 0; i < columnNames.length; i++) { + String columnName = columnNames[i]; + String columnType = columnTypes[i]; + columnsInfo.append(columnName).append(" ").append(columnType).append(", "); + } + return MessageFormat.format(CREATE_TABLE_QUERY, tableName, columnsInfo, pkColumnName); + } + + private static final String DROP_TABLE_QUERY = + "DROP TABLE {0}"; + public static String getDropTableQuery(String tableName) { + return MessageFormat.format(DROP_TABLE_QUERY, tableName); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java new file mode 100644 index 0000000..f9fb6db --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java @@ -0,0 +1,130 @@ +package mini.orm; + +import mini.orm.api.DatabaseService; +import mini.orm.model.CarEntity; +import mini.orm.model.IncorrectEntityWithoutColumnAnn; +import mini.orm.model.IncorrectEntityWithoutPrimaryKeyAnn; +import mini.orm.model.IncorrectEntityWithoutTableAnn; +import mini.orm.core.JdbcDatabaseService; +import org.h2.tools.Server; +import org.junit.*; + +import java.sql.SQLException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.List; + +import static org.junit.Assert.*; + +public class DatabaseServiceModuleTest { + private final DatabaseService carDbService = new JdbcDatabaseService<>(CarEntity.class); + + @Before + public void setUp() throws SQLException { + // start DB server + Server.createTcpServer("-tcpPort", "9001", "-tcpAllowOthers").start(); + // firstly create table + carDbService.createTable(); + } + + @After + public void setDown() throws SQLException { + // drop table if it exists + carDbService.dropTable(); + // stop DB server + Server.shutdownTcpServer("tcp://localhost:9001", "", true, true); + } + + @Test + public void restAllDmlOperations() throws ParseException { + // add data to table + final CarEntity car_1 = new CarEntity(); + car_1.setId(1); + car_1.setName("Car#1"); + car_1.setColor("green"); + car_1.setTruck(false); + car_1.setCountOfDoors(5); + car_1.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2010-12-01")); + + final CarEntity car_2 = new CarEntity(); + car_2.setId(2); + car_2.setName("Car#2"); + car_2.setColor("blue"); + car_2.setTruck(false); + car_2.setCountOfDoors(3); + car_2.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2013-01-20")); + + final CarEntity truck = new CarEntity(); + truck.setId(3); + truck.setName("MegaTruck"); + truck.setColor("grey"); + truck.setTruck(true); + truck.setCountOfDoors(2); + truck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2000-07-15")); + + carDbService.insert(car_1); + carDbService.insert(car_2); + carDbService.insert(truck); + + // select entity by primary key (car_2 expected) + CarEntity carByPK = carDbService.queryById(2); + assertNotNull(carByPK); + assertEquals(car_2, carByPK); + + CarEntity notExistedCar = carDbService.queryById(10); + assertNull(notExistedCar); + + // select all cars + List cars = carDbService.queryForAll(); + assertEquals(3, cars.size()); + assertTrue(cars.contains(car_1)); + assertTrue(cars.contains(car_2)); + assertTrue(cars.contains(truck)); + + // update any car + CarEntity newTruck = new CarEntity(); + newTruck.setId(3); + newTruck.setName("New TheMegaTruck"); + newTruck.setColor("dark-grey"); + newTruck.setTruck(true); + newTruck.setCountOfDoors(2); + newTruck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2015-07-15")); + carDbService.update(newTruck); + // select new truck and validate that it updated + CarEntity newTruckSelected = carDbService.queryById(3); + assertEquals(newTruck, newTruckSelected); + + // delete cars + carDbService.delete(car_1); + carDbService.delete(car_2); + // select all cars and check that deletion completed + List carsAfterDeletion = carDbService.queryForAll(); + assertEquals(1, carsAfterDeletion.size()); + assertTrue(carsAfterDeletion.contains(newTruck)); + + carDbService.delete(newTruck); + List noCarsAnymore = carDbService.queryForAll(); + assertTrue(noCarsAnymore.isEmpty()); + } + + @Test(expected = IllegalArgumentException.class) + public void testIncorrectEntity_WithoutTableAnnotation() { + DatabaseService dbService = + new JdbcDatabaseService<>(IncorrectEntityWithoutTableAnn.class); + dbService.queryForAll(); + } + + @Test(expected = IllegalArgumentException.class) + public void testIncorrectEntity_WithoutColumnAnnotation() { + DatabaseService dbService = + new JdbcDatabaseService<>(IncorrectEntityWithoutColumnAnn.class); + dbService.queryForAll(); + } + + @Test(expected = IllegalArgumentException.class) + public void testIncorrectEntity_WithoutPrimaryKeyAnnotation() { + DatabaseService dbService = + new JdbcDatabaseService<>(IncorrectEntityWithoutPrimaryKeyAnn.class); + dbService.queryForAll(); + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java new file mode 100644 index 0000000..2d6a917 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java @@ -0,0 +1,116 @@ +package mini.orm.model; + +import mini.orm.api.Column; +import mini.orm.api.PrimaryKey; +import mini.orm.api.Table; + +import java.util.Date; + +@Table(name = "cars") +public class CarEntity { + @PrimaryKey + @Column(name = "car_id") + private int id; + + @Column + private String name; + + @Column + private String color; + + @Column + private int countOfDoors; + + @Column(name = "is_truck") + private boolean truck; + + @Column + private Date releaseDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public int getCountOfDoors() { + return countOfDoors; + } + + public void setCountOfDoors(int countOfDoors) { + this.countOfDoors = countOfDoors; + } + + public boolean isTruck() { + return truck; + } + + public void setTruck(boolean truck) { + this.truck = truck; + } + + public Date getReleaseDate() { + return releaseDate; + } + + public void setReleaseDate(Date releaseDate) { + this.releaseDate = releaseDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CarEntity carEntity = (CarEntity) o; + + if (id != carEntity.id) return false; + if (countOfDoors != carEntity.countOfDoors) return false; + if (truck != carEntity.truck) return false; + if (name != null ? !name.equals(carEntity.name) : carEntity.name != null) return false; + if (color != null ? !color.equals(carEntity.color) : carEntity.color != null) return false; + return !(releaseDate != null ? !releaseDate.equals(carEntity.releaseDate) : carEntity.releaseDate != null); + + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (color != null ? color.hashCode() : 0); + result = 31 * result + countOfDoors; + result = 31 * result + (truck ? 1 : 0); + result = 31 * result + (releaseDate != null ? releaseDate.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CarEntity{" + + "id=" + id + + ", name='" + name + '\'' + + ", color='" + color + '\'' + + ", countOfDoors=" + countOfDoors + + ", truck=" + truck + + ", releaseDate=" + releaseDate + + '}'; + } +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java new file mode 100644 index 0000000..7ea367d --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java @@ -0,0 +1,15 @@ +package mini.orm.model; + +import mini.orm.api.Column; +import mini.orm.api.PrimaryKey; +import mini.orm.api.Table; + +@Table +public class IncorrectEntityWithoutColumnAnn { + + @PrimaryKey + @Column + private Integer id; + + private String name; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java new file mode 100644 index 0000000..7e73372 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java @@ -0,0 +1,14 @@ +package mini.orm.model; + +import mini.orm.api.Column; +import mini.orm.api.Table; + +@Table +public class IncorrectEntityWithoutPrimaryKeyAnn { + + @Column + private Integer id; + + @Column + private String name; +} \ No newline at end of file diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java new file mode 100644 index 0000000..bcb8634 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java @@ -0,0 +1,14 @@ +package mini.orm.model; + +import mini.orm.api.Column; +import mini.orm.api.PrimaryKey; + +public class IncorrectEntityWithoutTableAnn { + + @PrimaryKey + @Column + private Integer id; + + @Column + private String name; +} \ No newline at end of file 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 de55078..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 testEmptySourceQuery() throws IncorrectQueryException { - from(list(/* empty */)) - .select(Statistics.class) - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void testEmptyListOfSelectArgs() throws IncorrectQueryException { - from(list(new Object())).select(Object.class).execute(); - } - - @Test(expected = NullPointerException.class) - public void testNullResultClass() throws IncorrectQueryException { - from(list(new Object())).select(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void testNullWhereStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).where(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void testNullOrderByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).orderBy(null).execute(); - } - - @Test(expected = NullPointerException.class) - public void testNullGroupByStatement() 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 testEmptyGroupByStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).groupBy().execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void testIncorrectLimitStatement() throws IncorrectQueryException { - from(list(new Object())).select(Object.class, o -> 1).limit(0).execute(); - } - - @Test(expected = IncorrectQueryException.class) - public void testIncorrectSelectArguments() 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 testAggregateAndNotAggregateFunctionsInNotGroupingQuery() 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 931f9118bd5167fe1f31cfeabf00f8e029452236 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 14:10:11 +0300 Subject: [PATCH 13/20] checkstyle fixed --- .../MiniORM/src/checkstyle-suppressions.xml | 9 - .../liza22/MiniORM/src/checkstyle.xml | 175 ------------------ .../src/main/java/mini/orm/api/Column.java | 2 +- .../java/mini/orm/api/DatabaseService.java | 2 +- .../main/java/mini/orm/api/PrimaryKey.java | 2 +- .../src/main/java/mini/orm/api/Table.java | 2 +- .../mini/orm/core/JdbcDatabaseService.java | 2 +- .../mini/orm/core/db/ConnectionProvider.java | 2 +- .../main/java/mini/orm/core/db/DbConfig.java | 6 +- .../core/db/impl/JdbcConnectionProvider.java | 2 +- .../mini/orm/core/model/ColumnDescriptor.java | 2 +- .../mini/orm/core/model/TableDescriptor.java | 10 +- .../java/mini/orm/core/utils/Constants.java | 2 +- .../java/mini/orm/core/utils/NameUtils.java | 4 +- .../mini/orm/core/utils/QueryStorage.java | 11 +- .../mini/orm/DatabaseServiceModuleTest.java | 70 +++---- .../test/java/mini/orm/model/CarEntity.java | 81 ++++---- 17 files changed, 107 insertions(+), 277 deletions(-) delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml deleted file mode 100644 index ecd3542..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml deleted file mode 100644 index 3401cf5..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java index 1dc4837..f82e03d 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Column.java @@ -13,4 +13,4 @@ @Retention(value = RetentionPolicy.RUNTIME) public @interface Column { String name() default ""; -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java index 97f581e..413ae39 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/DatabaseService.java @@ -22,4 +22,4 @@ public interface DatabaseService { void createTable(); void dropTable(); -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java index 8c2c73d..4a462fd 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/PrimaryKey.java @@ -11,4 +11,4 @@ @Target(value = ElementType.FIELD) @Retention(value = RetentionPolicy.RUNTIME) public @interface PrimaryKey { -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java index 5d0133d..c4ad8c1 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/api/Table.java @@ -13,4 +13,4 @@ @Retention(value = RetentionPolicy.RUNTIME) public @interface Table { String name() default ""; -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java index 75d07e4..75832a9 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/JdbcDatabaseService.java @@ -179,4 +179,4 @@ private T buildEntityFromResult(ResultSet resultSet) { return null; } } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java index 6c72a78..b07e365 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/ConnectionProvider.java @@ -9,4 +9,4 @@ public interface ConnectionProvider { Connection getConnection() throws SQLException; -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java index 8da307e..2817a4b 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/DbConfig.java @@ -97,11 +97,11 @@ public final String getPassword() { @Override public final String toString() { - return "DbConfig{" - + "jdbcDriver='" + jdbcDriver + '\'' + return "DbConfig{" + + "jdbcDriver='" + jdbcDriver + '\'' + ", url='" + url + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java index 1c62237..0b1fb6b 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/db/impl/JdbcConnectionProvider.java @@ -21,4 +21,4 @@ public JdbcConnectionProvider() { public final Connection getConnection() throws SQLException { return DriverManager.getConnection(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword()); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java index bf90929..5fc8d36 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/ColumnDescriptor.java @@ -45,4 +45,4 @@ public static ColumnDescriptor fromEntityField(Field entityField) { Class columnType = entityField.getType(); return new ColumnDescriptor(columnName, columnType, entityField); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java index 1ff1cc5..701034c 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/model/TableDescriptor.java @@ -50,8 +50,8 @@ public ColumnDescriptor getPrimaryKey() { public static TableDescriptor fromEntityClass(Class entityClass) { if (!entityClass.isAnnotationPresent(Table.class)) { - throw new IllegalArgumentException("Class = " + entityClass.getSimpleName() - + " is not annotated by @Table"); + throw new IllegalArgumentException("Class = " + entityClass.getSimpleName() + + " is not annotated by @Table"); } String tableName = entityClass.getAnnotation(Table.class).name(); if (tableName.isEmpty()) { @@ -70,10 +70,10 @@ public static TableDescriptor fromEntityClass(Class entityClass) { } } if (!primaryKeyExists) { - throw new IllegalArgumentException("Entity class = " + entityClass.getSimpleName() - + " does not have @PrimaryKey field"); + throw new IllegalArgumentException("Entity class = " + entityClass.getSimpleName() + + " does not have @PrimaryKey field"); } return tableDescriptor; } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java index 9b784cf..07f9aca 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/Constants.java @@ -25,4 +25,4 @@ public class Constants { JAVA_TO_SQL_TYPES.put(String.class, "VARCHAR(256)"); JAVA_TO_SQL_TYPES.put(Date.class, "TIMESTAMP"); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java index fb0589f..6975465 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/NameUtils.java @@ -2,7 +2,7 @@ public final class NameUtils { - /** + /* * convert CamelCase format string to underscore format using regexp */ public static String convertFromCamelCaseToUnderscore(String ccStr) { @@ -10,4 +10,4 @@ public static String convertFromCamelCaseToUnderscore(String ccStr) { String replacement = "$1_$2"; return ccStr.replaceAll(regex, replacement).toLowerCase(); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java index a7a50aa..ced0024 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/main/java/mini/orm/core/utils/QueryStorage.java @@ -2,7 +2,7 @@ import java.text.MessageFormat; -/** +/* * this class contains SQL queries teplates. */ public class QueryStorage { @@ -51,10 +51,9 @@ public static String getDeleteByPkQuery(String tableName, String pkColumnName) { return MessageFormat.format(DELETE_BY_PK_QUERY, tableName, pkColumnName); } - private static final String CREATE_TABLE_QUERY = - "CREATE TABLE {0} ({1} PRIMARY KEY ( {2} ))"; - public static String getCreateTableQuery(String tableName, String[] columnNames, - String[] columnTypes, String pkColumnName) { + private static final String CREATE_TABLE_QUERY = "CREATE TABLE {0} ({1} PRIMARY KEY ( {2} ))"; + public static String getCreateTableQuery(String tableName, String[] columnNames, + String[] columnTypes, String pkColumnName) { StringBuilder columnsInfo = new StringBuilder(); for (int i = 0; i < columnNames.length; i++) { String columnName = columnNames[i]; @@ -69,4 +68,4 @@ public static String getCreateTableQuery(String tableName, String[] columnNames, public static String getDropTableQuery(String tableName) { return MessageFormat.format(DROP_TABLE_QUERY, tableName); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java index f9fb6db..23b6996 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java @@ -16,8 +16,12 @@ import static org.junit.Assert.*; -public class DatabaseServiceModuleTest { - private final DatabaseService carDbService = new JdbcDatabaseService<>(CarEntity.class); +public final class DatabaseServiceModuleTest { + private static final int N3 = 3; + private static final int N5 = 5; + private static final int N10 = 10; + + private DatabaseService carDbService = new JdbcDatabaseService<>(CarEntity.class); @Before public void setUp() throws SQLException { @@ -38,52 +42,52 @@ public void setDown() throws SQLException { @Test public void restAllDmlOperations() throws ParseException { // add data to table - final CarEntity car_1 = new CarEntity(); - car_1.setId(1); - car_1.setName("Car#1"); - car_1.setColor("green"); - car_1.setTruck(false); - car_1.setCountOfDoors(5); - car_1.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2010-12-01")); - - final CarEntity car_2 = new CarEntity(); - car_2.setId(2); - car_2.setName("Car#2"); - car_2.setColor("blue"); - car_2.setTruck(false); - car_2.setCountOfDoors(3); - car_2.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2013-01-20")); + final CarEntity car1 = new CarEntity(); + car1.setId(1); + car1.setName("Car#1"); + car1.setColor("green"); + car1.setTruck(false); + car1.setCountOfDoors(N5); + car1.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2010-12-01")); + + final CarEntity car2 = new CarEntity(); + car2.setId(2); + car2.setName("Car#2"); + car2.setColor("blue"); + car2.setTruck(false); + car2.setCountOfDoors(N3); + car2.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2013-01-20")); final CarEntity truck = new CarEntity(); - truck.setId(3); + truck.setId(N3); truck.setName("MegaTruck"); truck.setColor("grey"); truck.setTruck(true); truck.setCountOfDoors(2); truck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2000-07-15")); - carDbService.insert(car_1); - carDbService.insert(car_2); + carDbService.insert(car1); + carDbService.insert(car2); carDbService.insert(truck); // select entity by primary key (car_2 expected) CarEntity carByPK = carDbService.queryById(2); assertNotNull(carByPK); - assertEquals(car_2, carByPK); + assertEquals(car2, carByPK); - CarEntity notExistedCar = carDbService.queryById(10); + CarEntity notExistedCar = carDbService.queryById(N10); assertNull(notExistedCar); // select all cars List cars = carDbService.queryForAll(); - assertEquals(3, cars.size()); - assertTrue(cars.contains(car_1)); - assertTrue(cars.contains(car_2)); + assertEquals(N3, cars.size()); + assertTrue(cars.contains(car1)); + assertTrue(cars.contains(car2)); assertTrue(cars.contains(truck)); // update any car CarEntity newTruck = new CarEntity(); - newTruck.setId(3); + newTruck.setId(N3); newTruck.setName("New TheMegaTruck"); newTruck.setColor("dark-grey"); newTruck.setTruck(true); @@ -91,12 +95,12 @@ public void restAllDmlOperations() throws ParseException { newTruck.setReleaseDate(new SimpleDateFormat("YYYY-MM-DD").parse("2015-07-15")); carDbService.update(newTruck); // select new truck and validate that it updated - CarEntity newTruckSelected = carDbService.queryById(3); + CarEntity newTruckSelected = carDbService.queryById(N3); assertEquals(newTruck, newTruckSelected); // delete cars - carDbService.delete(car_1); - carDbService.delete(car_2); + carDbService.delete(car1); + carDbService.delete(car2); // select all cars and check that deletion completed List carsAfterDeletion = carDbService.queryForAll(); assertEquals(1, carsAfterDeletion.size()); @@ -108,23 +112,23 @@ public void restAllDmlOperations() throws ParseException { } @Test(expected = IllegalArgumentException.class) - public void testIncorrectEntity_WithoutTableAnnotation() { + public void testIncorrectEntityWithoutTableAnnotation() { DatabaseService dbService = new JdbcDatabaseService<>(IncorrectEntityWithoutTableAnn.class); dbService.queryForAll(); } @Test(expected = IllegalArgumentException.class) - public void testIncorrectEntity_WithoutColumnAnnotation() { + public void testIncorrectEntityWithoutColumnAnnotation() { DatabaseService dbService = new JdbcDatabaseService<>(IncorrectEntityWithoutColumnAnn.class); dbService.queryForAll(); } @Test(expected = IllegalArgumentException.class) - public void testIncorrectEntity_WithoutPrimaryKeyAnnotation() { + public void testIncorrectEntityWithoutPrimaryKeyAnnotation() { DatabaseService dbService = new JdbcDatabaseService<>(IncorrectEntityWithoutPrimaryKeyAnn.class); dbService.queryForAll(); } -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java index 2d6a917..1809b21 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java @@ -7,7 +7,10 @@ import java.util.Date; @Table(name = "cars") -public class CarEntity { +public final class CarEntity { + + private static final int CONST31 = 31; + @PrimaryKey @Column(name = "car_id") private int id; @@ -31,86 +34,94 @@ public int getId() { return id; } - public void setId(int id) { - this.id = id; + public void setId(int carid) { + this.id = carid; } public String getName() { return name; } - public void setName(String name) { - this.name = name; + public void setName(String carname) { + this.name = carname; } public String getColor() { return color; } - public void setColor(String color) { - this.color = color; + public void setColor(String carcolor) { + this.color = carcolor; } public int getCountOfDoors() { return countOfDoors; } - public void setCountOfDoors(int countOfDoors) { - this.countOfDoors = countOfDoors; + public void setCountOfDoors(int carcountOfDoors) { + this.countOfDoors = carcountOfDoors; } public boolean isTruck() { return truck; } - public void setTruck(boolean truck) { - this.truck = truck; + public void setTruck(boolean cartruck) { + this.truck = cartruck; } public Date getReleaseDate() { return releaseDate; } - public void setReleaseDate(Date releaseDate) { - this.releaseDate = releaseDate; + public void setReleaseDate(Date carreleaseDate) { + this.releaseDate = carreleaseDate; } @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } CarEntity carEntity = (CarEntity) o; - if (id != carEntity.id) return false; - if (countOfDoors != carEntity.countOfDoors) return false; - if (truck != carEntity.truck) return false; - if (name != null ? !name.equals(carEntity.name) : carEntity.name != null) return false; - if (color != null ? !color.equals(carEntity.color) : carEntity.color != null) return false; - return !(releaseDate != null ? !releaseDate.equals(carEntity.releaseDate) : carEntity.releaseDate != null); + if (id != carEntity.id) { return false; } + if (countOfDoors != carEntity.countOfDoors) { return false; } + if (truck != carEntity.truck) { return false; } + if (name != null && !name.equals(carEntity.name) || name == null && carEntity.name != null) { return false; } + if (color != null && !color.equals(carEntity.color) || + color == null && carEntity.color != null) { return false; } + return !(releaseDate != null && !releaseDate.equals(carEntity.releaseDate) || + releaseDate == null && carEntity.releaseDate != null); } @Override public int hashCode() { int result = id; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (color != null ? color.hashCode() : 0); - result = 31 * result + countOfDoors; - result = 31 * result + (truck ? 1 : 0); - result = 31 * result + (releaseDate != null ? releaseDate.hashCode() : 0); + result = CONST31 * result; + if (name != null) { result = result + name.hashCode(); } + result = CONST31 * result; + if (color != null) { result = result + color.hashCode(); } + result = CONST31 * result + countOfDoors; + result = CONST31 * result; + if (truck != 0) { result = result + 1; } + result = CONST31 * result; + if (releaseDate != null) { result = result + releaseDate.hashCode(); } return result; } @Override public String toString() { - return "CarEntity{" + - "id=" + id + - ", name='" + name + '\'' + - ", color='" + color + '\'' + - ", countOfDoors=" + countOfDoors + - ", truck=" + truck + - ", releaseDate=" + releaseDate + - '}'; + return "CarEntity{" + + "id=" + id + + ", name='" + name + + '\'' + + ", color='" + color + + '\'' + + ", countOfDoors=" + countOfDoors + + ", truck=" + truck + + ", releaseDate=" + releaseDate + + '}'; } -} \ No newline at end of file +} From 27a2ee88911717f71dc9b77cd5be34fc0e3d8691 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 14:10:54 +0300 Subject: [PATCH 14/20] checkstyle fixed --- .../java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java | 2 +- .../mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java | 2 +- .../java/mini/orm/model/IncorrectEntityWithoutTableAnn.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java index 7ea367d..ad670d0 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutColumnAnn.java @@ -12,4 +12,4 @@ public class IncorrectEntityWithoutColumnAnn { private Integer id; private String name; -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java index 7e73372..b836ce9 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutPrimaryKeyAnn.java @@ -11,4 +11,4 @@ public class IncorrectEntityWithoutPrimaryKeyAnn { @Column private String name; -} \ No newline at end of file +} diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java index bcb8634..3af530e 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/IncorrectEntityWithoutTableAnn.java @@ -11,4 +11,4 @@ public class IncorrectEntityWithoutTableAnn { @Column private String name; -} \ No newline at end of file +} From 47b31da0472d2d91aa1120947ee21d868adaf23c Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 14:20:09 +0300 Subject: [PATCH 15/20] checkstyle fixed --- .../test/java/mini/orm/model/CarEntity.java | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java index 1809b21..1b419f1 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java @@ -80,19 +80,33 @@ public void setReleaseDate(Date carreleaseDate) { @Override public boolean equals(Object o) { - if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { return false; } + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } CarEntity carEntity = (CarEntity) o; - if (id != carEntity.id) { return false; } - if (countOfDoors != carEntity.countOfDoors) { return false; } - if (truck != carEntity.truck) { return false; } - if (name != null && !name.equals(carEntity.name) || name == null && carEntity.name != null) { return false; } - if (color != null && !color.equals(carEntity.color) || - color == null && carEntity.color != null) { return false; } - return !(releaseDate != null && !releaseDate.equals(carEntity.releaseDate) || - releaseDate == null && carEntity.releaseDate != null); + if (id != carEntity.id) { + return false; + } + if (countOfDoors != carEntity.countOfDoors) { + return false; + } + if (truck != carEntity.truck) { + return false; + } + if (name != null && !name.equals(carEntity.name) || name == null && carEntity.name != null) { + return false; + } + if (color != null && !color.equals(carEntity.color) + || color == null && carEntity.color != null) { + return false; + } + return !(releaseDate != null && !releaseDate.equals(carEntity.releaseDate) + || releaseDate == null && carEntity.releaseDate != null); } @@ -100,14 +114,22 @@ public boolean equals(Object o) { public int hashCode() { int result = id; result = CONST31 * result; - if (name != null) { result = result + name.hashCode(); } + if (name != null) { + result = result + name.hashCode(); + } result = CONST31 * result; - if (color != null) { result = result + color.hashCode(); } + if (color != null) { + result = result + color.hashCode(); + } result = CONST31 * result + countOfDoors; result = CONST31 * result; - if (truck != 0) { result = result + 1; } + if (truck != 0) { + result = result + 1; + } result = CONST31 * result; - if (releaseDate != null) { result = result + releaseDate.hashCode(); } + if (releaseDate != null) { + result = result + releaseDate.hashCode(); + } return result; } From dc3370cf9029ebf43985ae097b2556a948999b26 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 15:00:14 +0300 Subject: [PATCH 16/20] pom.xml modified --- projects/liza22/pom.xml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml index 29abee2..6c4c1bc 100644 --- a/projects/liza22/pom.xml +++ b/projects/liza22/pom.xml @@ -16,17 +16,22 @@ UTF-8 - - junit - junit - 3.8.1 - test - - + org.twitter4j twitter4j-core [4.0,) + + com.h2database + h2 + 1.4.190 + + + junit + junit + 4.4 + test + org.twitter4j twitter4j-stream From 1dd0f5bc74deade489daaef82998b31fbff594d8 Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 15:07:46 +0300 Subject: [PATCH 17/20] delete other tasks --- projects/liza22/pom.xml | 16 +-- .../ru/mipt/diht/students/liza22/.gitignore | 1 - .../students/liza22/TwitterStream/pom.xml | 75 ------------ .../src/main/java/TwitterStream.java | 85 -------------- .../src/main/java/config/Arguments.java | 107 ------------------ .../src/main/java/config/Constants.java | 31 ----- .../src/main/java/config/TwitterConfig.java | 101 ----------------- .../main/java/core/handling/TweetHandler.java | 15 --- .../core/handling/TweetHandlerFactory.java | 26 ----- .../impl/PrintResultOfQueryTweetsHandler.java | 105 ----------------- .../impl/PrintStreamOfTweetsHandler.java | 101 ----------------- .../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 | 42 ------- .../src/main/java/utils/GeoUtils.java | 51 --------- .../src/main/java/utils/TextUtils.java | 16 --- .../TwitterStream/src/main/resources/help.txt | 11 -- ...1\203\320\272\321\206\320\270\321\217.txt" | Bin 162 -> 0 bytes 24 files changed, 6 insertions(+), 1218 deletions(-) delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java delete mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt delete 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/pom.xml b/projects/liza22/pom.xml index 6c4c1bc..16ebb3b 100644 --- a/projects/liza22/pom.xml +++ b/projects/liza22/pom.xml @@ -15,12 +15,12 @@ UTF-8 + + 1.7 + 1.7 + - - org.twitter4j - twitter4j-core - [4.0,) - + com.h2database h2 @@ -32,11 +32,7 @@ 4.4 test - - org.twitter4j - twitter4j-stream - [4.0,) - + com.beust jcommander 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 deleted file mode 100644 index 031401d..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/.gitignore +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index d3f7776..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 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 deleted file mode 100644 index 01aaba5..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/TwitterStream.java +++ /dev/null @@ -1,85 +0,0 @@ -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 final int LINE_LENGTH = 1024; - - 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 - */ - 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; - 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); - // 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(final 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[LINE_LENGTH]; - try (InputStream input = TwitterStream.class.getClassLoader().getResourceAsStream(Constants.HELP_FILE)) { - int length = input.read(buffer); - while (length != -1) { - out.write(buffer, 0, length); - length = input.read(buffer); - } - } - } 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 deleted file mode 100644 index 461846a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Arguments.java +++ /dev/null @@ -1,107 +0,0 @@ -package config; - -import com.beust.jcommander.Parameter; - -import java.util.List; - -/** - * Arguments storage. - * Used JCommander library. - * - * @see http://jcommander.org/ - */ -public final 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 deleted file mode 100644 index b9945af..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/Constants.java +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 9cee397..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/config/TwitterConfig.java +++ /dev/null @@ -1,101 +0,0 @@ -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 final AccessToken getAccessToken() { - return new AccessToken(accessToken, accessTokenSecret); - } - - public final Configuration getConfiguration() { - ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(). - setOAuthConsumerKey(consumerKey). - setOAuthConsumerSecret(consumerSecret). - setOAuthAccessToken(accessToken). - setOAuthAccessTokenSecret(accessTokenSecret); - return configurationBuilder.build(); - } - - @Override - 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/TweetHandler.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java deleted file mode 100644 index 01d81fc..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 807bc25..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/TweetHandlerFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -package core.handling; - -import core.handling.impl.PrintResultOfQueryTweetsHandler; -import core.handling.impl.PrintStreamOfTweetsHandler; -import model.Mode; - -public final 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 deleted file mode 100644 index b244d2e..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintResultOfQueryTweetsHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -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 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); - - public PrintResultOfQueryTweetsHandler(PrintStream outStream) { - this.out = outStream; - } - - @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(STRING_SIZE); - 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) / MILLI / SEC_IN_MIN; - 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 deleted file mode 100644 index 87e6e9a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/handling/impl/PrintStreamOfTweetsHandler.java +++ /dev/null @@ -1,101 +0,0 @@ -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 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; - - private boolean started = false; - private AtomicLong tweetCounter = new AtomicLong(0); - - public PrintStreamOfTweetsHandler(final PrintStream outStream) { - this.out = outStream; - 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 * KILO); - 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(STRING_SIZE); - 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 deleted file mode 100644 index e56766a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProvider.java +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 664dd46..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/TweetsProviderFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -package core.providing; - -import core.providing.impl.TweetsByQueryProvider; -import core.providing.impl.TweetsStreamProvider; -import model.Mode; - -/** - * Tweets provider factory. - */ -public final 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 deleted file mode 100644 index ba200c3..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsByQueryProvider.java +++ /dev/null @@ -1,65 +0,0 @@ -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 final 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 deleted file mode 100644 index cc4e514..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/providing/impl/TweetsStreamProvider.java +++ /dev/null @@ -1,96 +0,0 @@ -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 final 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 deleted file mode 100644 index 1b13f1a..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/FilterQueryBuilder.java +++ /dev/null @@ -1,55 +0,0 @@ -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 twiter) { - this.twitter = twiter; - } - - public final 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 deleted file mode 100644 index 3948ad3..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/core/quering/SearchQueryBuilder.java +++ /dev/null @@ -1,94 +0,0 @@ -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 twiter) { - this.twitter = twiter; - } - - public final 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 deleted file mode 100644 index 23dc708..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Mode.java +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 9ead43c..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/Tweet.java +++ /dev/null @@ -1,80 +0,0 @@ -package model; - -import twitter4j.Status; - -/** - * Class represents Tweet object. - */ -public final 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 tweetText) { - this.text = tweetText; - } - - public TwitterUser getAuthor() { - return author; - } - - public void setAuthor(TwitterUser tweetAuthor) { - this.author = tweetAuthor; - } - - public long getRetweetCount() { - return retweetCount; - } - - public void setRetweetCount(long count) { - this.retweetCount = count; - } - - public long getTime() { - return time; - } - - public void setTime(long tweetTime) { - this.time = tweetTime; - } - - public Tweet getRetweetedTweet() { - return retweetedTweet; - } - - public void setRetweetedTweet(Tweet retweeted) { - this.retweetedTweet = retweeted; - } - - 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 deleted file mode 100644 index a10e491..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/model/TwitterUser.java +++ /dev/null @@ -1,42 +0,0 @@ -package model; - -import twitter4j.User; - -/** - * Class represents Twitter User object. - */ -public class TwitterUser { - private Long id; - private String name; - - public TwitterUser(Long userid, String username) { - this.id = userid; - this.name = username; - } - - public final Long getId() { - return id; - } - - public final 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 final 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 deleted file mode 100644 index 662507b..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/GeoUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -package utils; - -import twitter4j.*; - -import static java.lang.Math.*; - -public final class GeoUtils { - public static final int CONST1 = 60; - public static final double CONST2 = 1.1515; - - 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 * CONST1 * CONST2; - 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 deleted file mode 100644 index e7f9304..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/java/utils/TextUtils.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 95008c4..0000000 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/TwitterStream/src/main/resources/help.txt +++ /dev/null @@ -1,11 +0,0 @@ -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/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" deleted file mode 100644 index 0ebf8fbd1362b5758a1d2024ba7e86bb95a56f28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmZR{$*f9bAQiAM Date: Sat, 19 Dec 2015 15:17:49 +0300 Subject: [PATCH 18/20] pom --- projects/liza22/pom.xml | 2 - .../MiniORM/src/checkstyle-suppressions.xml | 9 + .../liza22/MiniORM/src/checkstyle.xml | 175 ++++++++++++++++++ .../test/java/mini/orm/model/CarEntity.java | 2 +- 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml create mode 100644 projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml index 16ebb3b..ea2a311 100644 --- a/projects/liza22/pom.xml +++ b/projects/liza22/pom.xml @@ -14,8 +14,6 @@ http://maven.apache.org UTF-8 - - 1.7 1.7 diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml new file mode 100644 index 0000000..ecd3542 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle-suppressions.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml new file mode 100644 index 0000000..3401cf5 --- /dev/null +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/checkstyle.xml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java index 1b419f1..1db881c 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/model/CarEntity.java @@ -123,7 +123,7 @@ public int hashCode() { } result = CONST31 * result + countOfDoors; result = CONST31 * result; - if (truck != 0) { + if (truck) { result = result + 1; } result = CONST31 * result; From 478c91795341d2dc69215799a8d0102ff3bb7e7d Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 15:40:08 +0300 Subject: [PATCH 19/20] test modified --- .../src/test/java/mini/orm/DatabaseServiceModuleTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java index 23b6996..d9c6d68 100644 --- a/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java +++ b/projects/liza22/src/main/java/ru/mipt/diht/students/liza22/MiniORM/src/test/java/mini/orm/DatabaseServiceModuleTest.java @@ -7,7 +7,9 @@ import mini.orm.model.IncorrectEntityWithoutTableAnn; import mini.orm.core.JdbcDatabaseService; import org.h2.tools.Server; -import org.junit.*; +import org.junit.Test; +import org.junit.Before; +import org.junit.After; import java.sql.SQLException; import java.text.ParseException; From fc85e3f6a59e8af7b3591b77df0ec93ca03a249f Mon Sep 17 00:00:00 2001 From: liza22 Date: Sat, 19 Dec 2015 15:55:10 +0300 Subject: [PATCH 20/20] pom.xml modified --- projects/liza22/pom.xml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/projects/liza22/pom.xml b/projects/liza22/pom.xml index ea2a311..2c6271b 100644 --- a/projects/liza22/pom.xml +++ b/projects/liza22/pom.xml @@ -24,12 +24,19 @@ h2 1.4.190 - - junit + + org.powermock + powermock-module-junit4 + 1.6.1 + test + true + + junit - 4.4 - test - + junit + + + com.beust