-
Notifications
You must be signed in to change notification settings - Fork 0
pull #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dosstacy
wants to merge
48
commits into
branch
Choose a base branch
from
master
base: branch
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
pull #1
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
401a9b9
feat: add domain classes
2776890
feat: configuration for database
9235dba
feat: configuration for redis
35a31ea
feat: method of getting all data from mysql
875e3cb
feat: add country services
04e70ae
feat: add redis services
f826fc8
feat: add city services
e032662
feat: add classes with fields that often called in request
0d8f3df
refactor: move non business logic to CityDataProcessing class
2d8f1fe
refactor: move non business logic to CityDataProcessing class
b776079
refactor: move non business logic to CityDataProcessing class
647da17
style: comments delete
98a30a4
style: comments delete
e7acccf
style: comments delete
44a0692
feat: add city-country transformer
17ab566
feat: build feat
b948e6f
test: tests add
e0bf1ea
style: remove comments
1c354a0
refactor: names refactor
721adee
fix: add other lombok annotation instead of @Data which don't cause e…
933d766
refactor: add better structure for domain classes
de7cd6c
feat: add CrudRepository
809dadf
feat: add config class
37ce77f
feat: add repository classes
c59626f
feat: add more database queries
9c0db65
remove: remove unnecessary classes
bdb103a
feat: add customize exceptions
8276d0f
refactor: name changed
ed752cb
feat: add services
dc7907a
refactor: add methods
61e06e0
refactor: change variable type
928b932
fix: bug fixes
06b06ec
feat: add redis exception
1fccc38
fix: bug fixes
498cd0c
feat: add redis logic for the most requested items
733093f
feat: add config class
d32696d
fix: bugs fixed
820bc97
fix: bugs fixed
0bb5776
feat: add class for data transforming
f49de32
style: delete unused imports
db4c0cb
fix: bugs fixed
2d87e84
style: remove unnecessary code
5eddd8d
fix: bugs fixes
3422b10
test: add test class
30f8b6a
refactor: remove catches
f0bd420
refactor: edit logs
18f463f
refactor: edit pom.xml
ce4838b
refactor: edit main
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <groupId>com.example</groupId> | ||
| <artifactId>my-project</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
|
|
||
| <properties> | ||
| <maven.compiler.source>8</maven.compiler.source> | ||
| <maven.compiler.target>8</maven.compiler.target> | ||
| </properties> | ||
|
|
||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>mysql</groupId> | ||
| <artifactId>mysql-connector-java</artifactId> | ||
| <version>8.0.30</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.hibernate</groupId> | ||
| <artifactId>hibernate-core-jakarta</artifactId> | ||
| <version>5.6.14.Final</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>p6spy</groupId> | ||
| <artifactId>p6spy</artifactId> | ||
| <version>3.9.1</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>io.lettuce</groupId> | ||
| <artifactId>lettuce-core</artifactId> | ||
| <version>6.2.2.RELEASE</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <version>1.18.30</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-core</artifactId> | ||
| <version>5.12.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.mockito</groupId> | ||
| <artifactId>mockito-junit-jupiter</artifactId> | ||
| <version>5.12.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| <version>2.0.13</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>com.fasterxml.jackson.core</groupId> | ||
| <artifactId>jackson-databind</artifactId> | ||
| <version>2.14.0</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>redis.clients</groupId> | ||
| <artifactId>jedis</artifactId> | ||
| <version>5.2.0</version> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <version>3.8.1</version> | ||
| <configuration> | ||
| <source>21</source> | ||
| <target>21</target> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| package com.javarush; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.javarush.cache.RedisRepository; | ||
| import com.javarush.config.HibernateUtil; | ||
| import com.javarush.config.RedisConfig; | ||
| import com.javarush.domain.entity.City; | ||
| import com.javarush.domain.entity.CountryLanguage; | ||
| import com.javarush.redis.CityCountry; | ||
| import com.javarush.repository.CityRepository; | ||
| import com.javarush.repository.CountryRepository; | ||
| import com.javarush.services.CityService; | ||
| import com.javarush.services.CountryService; | ||
| import io.lettuce.core.RedisClient; | ||
| import io.lettuce.core.api.StatefulRedisConnection; | ||
| import io.lettuce.core.api.sync.RedisStringCommands; | ||
| import org.hibernate.Session; | ||
| import org.hibernate.SessionFactory; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Set; | ||
|
|
||
| import static java.util.Objects.nonNull; | ||
|
|
||
| public class Application { | ||
| public final SessionFactory sessionFactory; | ||
| public final RedisClient redisClient; | ||
| public final CityService cityService; | ||
| public final CountryService countryService; | ||
| public final ObjectMapper mapper; | ||
| private static final Logger LOGGER = LoggerFactory.getLogger(Application.class); | ||
|
|
||
| public Application() { | ||
| sessionFactory = HibernateUtil.getSessionFactory(); | ||
| redisClient = RedisConfig.prepareRedisClient(); | ||
| cityService = new CityService(new RedisRepository(), new CityRepository()); | ||
| countryService = new CountryService(new RedisRepository(), new CountryRepository()); | ||
| mapper = new ObjectMapper(); | ||
| } | ||
|
|
||
| private void shutdown() { | ||
| if (nonNull(sessionFactory)) { | ||
| sessionFactory.close(); | ||
| } | ||
| if (nonNull(redisClient)) { | ||
| redisClient.shutdown(); | ||
| } | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| int numOfQueries = 15; | ||
| Application application = new Application(); | ||
| RedisRepository countryRedisRepository = new RedisRepository(); | ||
| RedisRepository cityRedisRepository = new RedisRepository(); | ||
|
|
||
| System.out.println("Querying Country by ID..."); | ||
| for (int i = 0; i < numOfQueries; i++) { | ||
| application.countryService.getById(1); | ||
| application.cityService.getById(2); | ||
| } | ||
| } | ||
|
|
||
| private void pushToRedis(List<CityCountry> data) { | ||
| try (StatefulRedisConnection<String, String> connection = redisClient.connect()) { | ||
| RedisStringCommands<String, String> sync = connection.sync(); | ||
| for (CityCountry cityCountry : data) { | ||
| try { | ||
| sync.set(String.valueOf(cityCountry.getId()), mapper.writeValueAsString(cityCountry)); | ||
| } catch (JsonProcessingException e) { | ||
| LOGGER.error("Couldn't push to redis : ", e); | ||
| e.printStackTrace(System.out); | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
|
|
||
| private void testRedisData(List<Integer> ids) { | ||
| try (StatefulRedisConnection<String, String> connection = redisClient.connect()) { | ||
| RedisStringCommands<String, String> sync = connection.sync(); | ||
| for (Integer id : ids) { | ||
| String value = sync.get(String.valueOf(id)); | ||
| try { | ||
| mapper.readValue(value, CityCountry.class); | ||
| } catch (JsonProcessingException e) { | ||
| LOGGER.error("Couldn't test redis data : ", e); | ||
| e.printStackTrace(System.out); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void testMysqlData(List<Integer> ids) { | ||
| try (Session session = sessionFactory.getCurrentSession()) { | ||
| session.beginTransaction(); | ||
| for (Integer id : ids) { | ||
| City city = cityService.getById(id); | ||
| Set<CountryLanguage> languages = city.getCountryId().getLanguages(); | ||
| } | ||
| session.getTransaction().commit(); | ||
| } | ||
| } | ||
|
|
||
| public List<City> fetchData() { | ||
| try (Session session = sessionFactory.getCurrentSession()) { | ||
| List<City> allCities = new ArrayList<>(); | ||
| session.beginTransaction(); | ||
|
|
||
| countryService.getAll(); | ||
|
|
||
| int totalCount = cityService.getTotalCount(); | ||
| int step = 500; | ||
| for (int i = 0; i < totalCount; i += step) { | ||
| allCities.addAll(cityService.getItems(i, step)); | ||
| } | ||
| session.getTransaction().commit(); | ||
| return allCities; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package com.javarush; | ||
|
|
||
| import com.javarush.domain.entity.City; | ||
| import com.javarush.domain.entity.Country; | ||
| import com.javarush.domain.entity.CountryLanguage; | ||
| import com.javarush.redis.CityCountry; | ||
| import com.javarush.redis.Language; | ||
|
|
||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class DataTransformer { | ||
| public static CityCountry countryTransformToCityCountry(Country country) { | ||
| CityCountry res = new CityCountry(); | ||
| res.setAlternativeCountryCode(country.getCode2()); | ||
| res.setContinent(country.getContinent()); | ||
| res.setCountryCode(country.getCode()); | ||
| res.setCountryName(country.getName()); | ||
| res.setCountryPopulation(country.getPopulation()); | ||
| res.setCountryRegion(country.getRegion()); | ||
| res.setCountrySurfaceArea(country.getSurfaceArea()); | ||
| Set<CountryLanguage> countryLanguages = country.getLanguages(); | ||
| Set<Language> languages = countryLanguages.stream().map(cl -> { | ||
| Language language = new Language(); | ||
| language.setLanguage(cl.getLanguage()); | ||
| language.setIsOfficial(cl.getIsOfficial()); | ||
| language.setPercentage(cl.getPercentage()); | ||
| return language; | ||
| }).collect(Collectors.toSet()); | ||
| res.setLanguages(languages); | ||
| return res; | ||
| } | ||
|
|
||
| public static CityCountry cityTransformToCityCountry(City city) { | ||
| CityCountry res = new CityCountry(); | ||
| res.setId(city.getId()); | ||
| res.setName(city.getName()); | ||
| res.setPopulation(city.getPopulation()); | ||
| res.setDistrict(city.getDistrict()); | ||
| return res; | ||
| } | ||
|
|
||
| public static City cityCountryTransformToCity(CityCountry cityCountry) { | ||
| City city = new City(); | ||
| city.setId(cityCountry.getId()); | ||
| city.setName(cityCountry.getName()); | ||
| city.setPopulation(cityCountry.getPopulation()); | ||
| city.setDistrict(cityCountry.getDistrict()); | ||
| return city; | ||
| } | ||
|
|
||
| public static Country cityCountryToCountry(CityCountry cityCountry) { | ||
| Country country = new Country(); | ||
| country.setCode2(cityCountry.getAlternativeCountryCode()); | ||
| country.setContinent(cityCountry.getContinent()); | ||
| country.setCode(cityCountry.getCountryCode()); | ||
| country.setName(cityCountry.getCountryName()); | ||
| country.setPopulation(cityCountry.getCountryPopulation()); | ||
| country.setRegion(cityCountry.getCountryRegion()); | ||
| country.setSurfaceArea(cityCountry.getCountrySurfaceArea()); | ||
| Set<Language> languages = cityCountry.getLanguages(); | ||
| Set<CountryLanguage> countryLanguages = languages.stream().map(cl -> { | ||
| CountryLanguage countryLanguage = new CountryLanguage(); | ||
| countryLanguage.setLanguage(cl.getLanguage()); | ||
| countryLanguage.setIsOfficial(cl.getIsOfficial()); | ||
| countryLanguage.setPercentage(cl.getPercentage()); | ||
| return countryLanguage; | ||
| }).collect(Collectors.toSet()); | ||
| country.setLanguages(countryLanguages); | ||
| return country; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package com.javarush.cache; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.javarush.services.CityService; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import redis.clients.jedis.UnifiedJedis; | ||
| import redis.clients.jedis.util.SafeEncoder; | ||
|
|
||
| public class RedisRepository { | ||
| private final UnifiedJedis jedis; | ||
| private final ObjectMapper objectMapper = new ObjectMapper(); | ||
| private static final String TOPK_NAME = "city-country"; | ||
| private static final int THRESHOLD = 7; | ||
| private static final Logger LOGGER = LoggerFactory.getLogger(CityService.class); | ||
| private static final String REDIS_URL = "redis://127.0.0.1:6379"; | ||
| private static final String BRACES_REGEX = "[\\[\\]]"; | ||
|
|
||
| public RedisRepository() { | ||
| jedis = new UnifiedJedis(REDIS_URL); | ||
|
|
||
| jedis.del(TOPK_NAME); | ||
| if (!jedis.exists(TOPK_NAME)) { | ||
| jedis.topkReserve(TOPK_NAME, 5L, 2000L, 7L, 0.925D); | ||
| } | ||
| } | ||
|
|
||
| public <T> T getById(String key, Class<T> clazz) throws JsonProcessingException { | ||
| String serializedEntity = jedis.get(key); | ||
| return deserialize(serializedEntity, clazz); | ||
| } | ||
|
|
||
| public <T> void put(String key, T value) throws JsonProcessingException { | ||
| jedis.topkAdd(TOPK_NAME, key); | ||
|
|
||
| if (getCount(key) >= THRESHOLD) { | ||
| jedis.set(key, serialize(value)); | ||
| } | ||
| } | ||
|
|
||
| private int getCount(String key) { | ||
| String count = jedis.sendCommand(() -> SafeEncoder.encode("TOPK.COUNT"), SafeEncoder.encodeMany(TOPK_NAME, key)).toString(); | ||
| return Integer.parseInt(count.replaceAll(BRACES_REGEX, "")); | ||
| } | ||
|
|
||
| public boolean checkExists(String key) { | ||
| return jedis.exists(key); | ||
| } | ||
|
|
||
| private <T> String serialize(T entity) throws JsonProcessingException { | ||
| return objectMapper.writeValueAsString(entity); | ||
| } | ||
|
|
||
| private <T> T deserialize(String serializedEntity, Class<T> clazz) throws JsonProcessingException { | ||
| return objectMapper.readValue(serializedEntity, clazz); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package com.javarush.config; | ||
|
|
||
| import com.javarush.domain.entity.City; | ||
| import com.javarush.domain.entity.Country; | ||
| import com.javarush.domain.entity.CountryLanguage; | ||
| import org.hibernate.SessionFactory; | ||
| import org.hibernate.cfg.Configuration; | ||
| import org.hibernate.cfg.Environment; | ||
|
|
||
| import java.util.Properties; | ||
|
|
||
| public class HibernateUtil { | ||
| private static SessionFactory sessionFactory; | ||
|
|
||
| private HibernateUtil() { | ||
|
|
||
| } | ||
|
|
||
| private static SessionFactory prepareRelationalDb() { | ||
| final SessionFactory sessionFactory; | ||
| Properties properties = new Properties(); | ||
| properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQL8Dialect"); | ||
| properties.put(Environment.DRIVER, "com.p6spy.engine.spy.P6SpyDriver"); | ||
| properties.put(Environment.URL, "jdbc:p6spy:mysql://localhost:3306/world"); | ||
| properties.put(Environment.USER, "root"); | ||
| properties.put(Environment.PASS, "root"); | ||
| properties.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread"); | ||
| properties.put(Environment.HBM2DDL_AUTO, "validate"); | ||
| properties.put(Environment.STATEMENT_BATCH_SIZE, "100"); | ||
|
|
||
| sessionFactory = new Configuration() | ||
| .addAnnotatedClass(City.class) | ||
| .addAnnotatedClass(Country.class) | ||
| .addAnnotatedClass(CountryLanguage.class) | ||
| .addProperties(properties) | ||
| .buildSessionFactory(); | ||
| return sessionFactory; | ||
| } | ||
|
|
||
| public static SessionFactory getSessionFactory() { | ||
| if (sessionFactory == null) { | ||
| sessionFactory = prepareRelationalDb(); | ||
| } | ||
| return sessionFactory; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first dependency, then plugins