Compare commits

...

No commits in common. "PROJEKT-1" and "PROJEKT-2" have entirely different histories.

29 changed files with 3126 additions and 562 deletions

View File

@ -1,26 +1,40 @@
# PRA2024 # PRA2024
Pracownia Programowania - przyrost1 Pracownia Programowania - Projekt 2
Autor: Marcin Hutek s485949 Autor: Marcin Hutek s485949
Wykorzystana baza danych zostala przygotowana przy uzyciu PostgreSQL i zawiera cztery tabele: 'films',
'films_info', 'category' oraz 'language'. Baza zostala wstepnie spopulowana tysiacem rekordow.
Backup bazy z jej kodem zrodlowym PRA2024.sql wygenerowany przy pomocy
komendy pg_dump umieszczony został w folderze database w drzewku projektu.
## ZMAPOWANE ENCJE ##
#### FilmModel ####
- zmapowana podstawowa encja 'films' z bazy danych zawierajaca kolumny: 'film_id', 'film_title'
- w relacji OneToOne z encją FilmInfoModel
#### FilmInfoModel ####
- zmapowana encja 'films_info' bazy danych zawierajaca kolumny: 'film_id', 'description', 'release_year',
'language_id', 'length', 'rating', 'category_id' oraz pole ZonedDateTime - 'last_update'
- w relacji OneToOne z encją FilmModel
- w relacji ManyToOne z encją FilmCategoryModel
- w relacji ManyToOne z encją FilmLanguageModel
#### FilmCategoryModel ####
- zmapowana encja 'category' bazy danych zawierajaca kolumny: 'category_id', 'name'
- w relacji OneToMany z encją FilmInfoModel
#### FilmLanguageModel ####
- zmapowana encja 'language' bazy danych zawierajaca kolumny: 'language_id', 'language'
- w relacji OneToMany z encją FilmInfoModel
## SESJA ORAZ ZAPYTANIA ##
#### Main #### #### Main ####
- główna pętla programu - zdefiniowanie sesji oraz wywolanie poszczegolnych zapytan
#### CityNames #### #### Queries ####
- odczytanie i wyswietlenie w konsoli nazw dostepnych miast z przygotowanego wczesniej pliku .json. - dwa query z parametrem: getFilmByLangYear oraz getFilmByLangCategory
- wykorzystatnie strumienia - query stronicowane: getAllFilmsByPage
#### JsonToMap #### - metoda sluzaca do tworzenia nowych rekordow w bazie: createFilmModel
- polaczenie listy dostepnych miast i ich koordynatow na podstawie przygotowanego pliku .json
- wykorzystanie mapy ## TESTY ##
#### HttpClient #### #### QueriesTest ####
- utworzenie klienta Http i wykonanie GET request'a - dla kazdego zapytania przygotowane zostaly po dwa przykladowe testy mockujace
#### WeatherForecast #### - dla metody sluzacej do dodawania rekordow do bazy przygotowany zostal jeden przykladowy test
- zdefiniowanie obiektu skupiajacego pobrane dane dotyczace pogody dla danego miasta mockujacy sesje i sprawdzajacy czy rekord zostal poprawnie utworzony
- metoda wyswietlajaca w konsoli lancuch tekstowy zawierajacy dane o pogodzie dla wskazanego
przez uzytkownika miasta
- metody zapisu do poszczegolnych formatow - do json i xml wykorzystana zostala lista wyzej wspomnianych obiektow,
do pdf wykorzystany zostal utworzony w tym celu plik textowy temporary_file
#### ForecastPreparation ####
- odczytanie z odpowiedzi API odpowiednich danych na temat prognoz
- utworzenie obiektu weatherForecast skupiajacego te dane
#### TemporaryFile ####
- utworzenie pustego pliku txt w ktorym przechowywana jest lista pobrany prognoz w danej sesji
#### TESTY ####
- zgodnie z wymaganiami projektu przygotowano 3 testy mockujace dla klasy HttpClient

View File

@ -1,27 +0,0 @@
[
{
"name": "warsaw",
"latitude": 52.24,
"longitude": 21.02
},
{
"name": "berlin",
"latitude": 52.52,
"longitude": 13.40
},
{
"name": "chicago",
"latitude": 41.88,
"longitude": -87.62
},
{
"name": "vancouver",
"latitude": 49.25,
"longitude": -123.12
},
{
"name": "tokyo",
"latitude": 35.65,
"longitude": 139.84
}
]

2319
database/PRA2024.sql Normal file

File diff suppressed because it is too large Load Diff

47
pom.xml
View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <groupId>org.example</groupId>
<artifactId>testy</artifactId> <artifactId>PRA2024</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<properties> <properties>
@ -13,37 +13,22 @@
<maven.compiler.target>18</maven.compiler.target> <maven.compiler.target>18</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>org.hibernate.orm</groupId>
<artifactId>jackson-dataformat-xml</artifactId> <artifactId>hibernate-core</artifactId>
<version>2.15.1</version> <version>6.4.1.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.postgresql</groupId>
<artifactId>httpclient</artifactId> <artifactId>postgresql</artifactId>
<version>4.5.13</version> <version>42.2.20</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -53,14 +38,16 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>org.eclipse.jdt</groupId>
<artifactId>commons-io</artifactId> <artifactId>ecj</artifactId>
<version>2.11.0</version> <version>3.28.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>org.mockito</groupId>
<artifactId>jackson-dataformat-xml</artifactId> <artifactId>mockito-core</artifactId>
<version>2.13.1</version> <version>4.8.0</version>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

Binary file not shown.

View File

@ -0,0 +1 @@
[{"cityName":"chicago","description":"few clouds","temperature":276.59,"pressure":1029,"humidity":50}]

View File

@ -0,0 +1,37 @@
%PDF-1.4
%âãÏÓ
2 0 obj
<</Length 185/Filter/FlateDecode>>stream
xœåÏ; Â0†á=¿â,B…“Ö^GA…lÅ!6F{3I)þ{ÓQX\=Óžá{ŸhGQ”@† aH6?½!¯æUÀÄ”fÓšÞ­ÁÔãBWJFö]WÕ?D<55>\;¹í åñR@˜&~†<>tPBëÙÕ'f%Á8vºzl%·3Ë•UùÖiÇ9áö^…jd÷½·•Ú,ÌLý8Z™çdAeøK垢3zŒ¾e
endstream
endobj
4 0 obj
<</Type/Page/MediaBox[0 0 595 842]/Resources<</Font<</F1 1 0 R>>>>/Contents 2 0 R/Parent 3 0 R>>
endobj
1 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
endobj
3 0 obj
<</Type/Pages/Count 1/Kids[4 0 R]>>
endobj
5 0 obj
<</Type/Catalog/Pages 3 0 R>>
endobj
6 0 obj
<</Producer(iText® 5.5.13 ©2000-2018 iText Group NV \(AGPL-version\))/CreationDate(D:20231212210957+01'00')/ModDate(D:20231212210957+01'00')>>
endobj
xref
0 7
0000000000 65535 f
0000000379 00000 n
0000000015 00000 n
0000000467 00000 n
0000000267 00000 n
0000000518 00000 n
0000000563 00000 n
trailer
<</Size 7/Root 5 0 R/Info 6 0 R/ID [<7473657c6d90d07a2455d7e52ef9a859><7473657c6d90d07a2455d7e52ef9a859>]>>
%iText-5.5.13
startxref
721
%%EOF

View File

@ -0,0 +1 @@
[

View File

@ -0,0 +1 @@
[{"cityName":"chicago","description":"scattered clouds","temperature":276.63,"pressure":1030,"humidity":50},{"cityName":"berlin","description":"mist","temperature":277.53,"pressure":991,"humidity":92}]

View File

@ -0,0 +1 @@
<ArrayList><item><cityName>vancouver</cityName><description>broken clouds</description><temperature>278.92</temperature><pressure>1024</pressure><humidity>91</humidity></item><item><cityName>warsaw</cityName><description>broken clouds</description><temperature>276.8</temperature><pressure>1005</pressure><humidity>94</humidity></item></ArrayList>

View File

@ -0,0 +1 @@
<ArrayList><item><cityName>berlin</cityName><description>light intensity drizzle rain</description><temperature>278.87</temperature><pressure>981</pressure><humidity>94</humidity></item><item><cityName>berlin</cityName><description>light intensity drizzle rain</description><temperature>278.87</temperature><pressure>981</pressure><humidity>94</humidity></item><item><cityName>warsaw</cityName><description>broken clouds</description><temperature>277.17</temperature><pressure>999</pressure><humidity>91</humidity></item></ArrayList>

Binary file not shown.

View File

@ -0,0 +1,37 @@
%PDF-1.4
%âãÏÓ
2 0 obj
<</Length 191/Filter/FlateDecode>>stream
xœíÏ= Â0€á=¿âA¡Å6…6í(èâ¢<C3A2>­8¤Í‰Ñ~™¤ÿ½íXTgÍtÃsGÞ'ÙqÅÀ‚¸$ø!›†í!„<>¿u©ì+ƒu¥š ¿<>&˜ÑµDSjÕYÕ6˜RX%”UÛKãÜ°Xw¨…í5æÇK”Q/Žœ´ÓhÌän'1Ê4aNvëk%Ç<>æ«1÷)ßñœðW¡<> Ý>°ù*7I=š~”ËÜlÒîbîž“3yÈé
endstream
endobj
4 0 obj
<</Type/Page/MediaBox[0 0 595 842]/Resources<</Font<</F1 1 0 R>>>>/Contents 2 0 R/Parent 3 0 R>>
endobj
1 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
endobj
3 0 obj
<</Type/Pages/Count 1/Kids[4 0 R]>>
endobj
5 0 obj
<</Type/Catalog/Pages 3 0 R>>
endobj
6 0 obj
<</Producer(iText® 5.5.13 ©2000-2018 iText Group NV \(AGPL-version\))/CreationDate(D:20240103192046+01'00')/ModDate(D:20240103192046+01'00')>>
endobj
xref
0 7
0000000000 65535 f
0000000385 00000 n
0000000015 00000 n
0000000473 00000 n
0000000273 00000 n
0000000524 00000 n
0000000569 00000 n
trailer
<</Size 7/Root 5 0 R/Info 6 0 R/ID [<76c69ed41a734d16189b7f47c42dd959><76c69ed41a734d16189b7f47c42dd959>]>>
%iText-5.5.13
startxref
727
%%EOF

View File

@ -1,35 +0,0 @@
package model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
/*
Klasa odczytujaca oraz wypisujaca dostepne miasta z pliku .json.
Wykorzystanie strumienia.
*/
public class CityNames {
public static void cityNamesRead(String filePath) {
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonArray = objectMapper.readTree(new File(filePath));
List<String> cityNames = jsonArray
.findValuesAsText("name")
.stream()
.collect(Collectors.toList());
System.out.println("Dostępne miasta:");
cityNames.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,28 +0,0 @@
package model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
/*
Klasa odczytujaca z odpowiedzi API wyamagane informacje o prognozie pogody.
*/
public class ForecastPreparation {
public static weatherForecast fetchForecastData(String cityName, String response) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(response);
String description = rootNode.get("weather").get(0).get("description").asText();
double temperature = rootNode.get("main").get("temp").asDouble();
int pressure = rootNode.get("main").get("pressure").asInt();
int humidity = rootNode.get("main").get("humidity").asInt();
return new weatherForecast(cityName, description, temperature, pressure, humidity);
}
}

View File

@ -1,49 +0,0 @@
package model;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
/*
Klasa tworzaca klienta Http i wykonujaca zapytanie GET
*/
public class HttpClient {
private CloseableHttpClient httpClient;
public HttpClient() {
this.httpClient = HttpClients.createDefault();
}
public HttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
}
// public void setHttpClient(CloseableHttpClient httpClient) {
// this.httpClient = httpClient;
// }
public String executeGetRequest(String urlString) {
HttpGet request = new HttpGet(urlString);
try (CloseableHttpResponse response = httpClient.execute(request)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toString(entity);
}
return "";
} catch (ClientProtocolException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,39 +0,0 @@
package model;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/*
Klasa laczaca dostepne nazwy miast i ich koordynaty w mape.
*/
public class JsonToMap {
public static Map<String, Map<String, Double>> createCityMap(String jsonFile) {
Map<String, Map<String, Double>> cityMap = new HashMap<>();
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonArray = objectMapper.readTree(new File(jsonFile));
for (JsonNode jsonNode : jsonArray) {
String cityName = jsonNode.get("name").asText();
double latitude = jsonNode.get("latitude").asDouble();
double longitude = jsonNode.get("longitude").asDouble();
Map<String, Double> cordsMap = new HashMap<>();
cordsMap.put("latitude", latitude);
cordsMap.put("longitude", longitude);
cityMap.put(cityName, cordsMap);
}
} catch (IOException e) {
e.printStackTrace();
}
return cityMap;
}
}

View File

@ -1,32 +0,0 @@
package model;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/*
Klasa tworzaca pusty plik temporary.
*/
public class TemporaryFile {
public static final String FILE_NAME = "temporary_file.txt";
public void createEmptyFile() {
try {
FileWriter fileWriter = new FileWriter(FILE_NAME);
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void addToFile(String fileInput) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_NAME, true));
writer.write(fileInput + "\n");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,105 +0,0 @@
package model;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.itextpdf.text.Document;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
/*
Klasa weatherForecast zawierajaca metody pozwalajace na zapis do poszczegolnych formatow.
Obiekty tworzone poprzez wywolanie klasy zbierane sa do listy ulatwiajacej generacje plikow json i xml.
Do zapisu do pdf wykorzystywany jest plik temporary zbierajacy wywolane prognozy w formacie txt.
*/
public class weatherForecast {
public static final List<weatherForecast> allEntries = new ArrayList<>();
private final String cityName;
private final String description;
private final double temperature;
private final int pressure;
private final int humidity;
public weatherForecast(String cityName, String description, double temperature,
int pressure, int humidity) {
this.cityName = cityName;
this.description = description;
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
allEntries.add(this);
}
public String prepareForecastString() {
String weatherForecastString = String.format("""
city: %s
description: %s
temperature[K]: %.2f
pressure[hPa]: %d
humidity[%%]: %d
--------------------""", this.cityName, this.description, this.temperature,
this.pressure, this.humidity);
return weatherForecastString;
}
public static void saveToJson(String outputFile) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File(outputFile), allEntries);
}
public static void saveToXml(String outputFile) throws IOException {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.writeValue(new File(outputFile), allEntries);
}
public static void saveToPdf(String inputFile, String outputFile) {
try (BufferedReader br = new BufferedReader(new FileReader(inputFile))) {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(outputFile));
document.open();
String line;
while ((line = br.readLine()) != null) {
document.add(new Paragraph(line));
}
document.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static List<weatherForecast> getAllEntries() {
return new ArrayList<>(allEntries);
}
public String getCityName() {
return cityName;
}
public String getDescription() {
return description;
}
public double getTemperature() {
return temperature;
}
public int getPressure() {
return pressure;
}
public int getHumidity() {
return humidity;
}
}

View File

@ -0,0 +1,50 @@
package org.example;
import jakarta.persistence.*;
import java.util.List;
@Entity
@Table(name="category")
public class FilmCategoryModel {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="category_id")
private int id;
@Column(name="name")
private String filmCategory;
public FilmCategoryModel() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFilmCategory() {
return filmCategory;
}
public void setFilmCategory(String filmCategory) {
this.filmCategory = filmCategory;
}
@OneToMany(mappedBy = "filmCategoryModel", fetch = FetchType.LAZY)
private List<FilmInfoModel> filmInfoModel;
public FilmInfoModel getFilmInfo() {
return (FilmInfoModel) filmInfoModel;
}
@Override
public String toString() {
return "Category{" +
"id=" + id +
", filmCategory='" + filmCategory + '}';
}
}

View File

@ -0,0 +1,140 @@
package org.example;
import jakarta.persistence.*;
import java.time.ZonedDateTime;
@Entity
@Table(name="films_info")
public class FilmInfoModel {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="film_id")
private int id;
@Column(name="description")
private String filmDescription;
@Column(name="release_year")
private int releaseYear;
@Column(name="language_id")
private int filmLanguage;
@Column(name="length")
private int filmLength;
@Column(name="rating")
private String filmRating;
@Column(name="category_id")
private int filmCategory;
@Column(name="last_update", columnDefinition = "TIMESTAMP WITH TIME ZONE")
private ZonedDateTime lastUpdate;
public FilmInfoModel() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFilmDescription() {
return filmDescription;
}
public void setFilmDescription(String filmDescription) {
this.filmDescription = filmDescription;
}
public int getReleaseYear() {
return releaseYear;
}
public void setReleaseYear(int releaseYear) {
this.releaseYear = releaseYear;
}
public int getFilmLanguage() {
return filmLanguage;
}
public void setFilmLanguage(int filmLanguage) {
this.filmLanguage = filmLanguage;
}
public int getFilmLength() {
return filmLength;
}
public void setFilmLength(int filmLength) {
this.filmLength = filmLength;
}
public String getFilmRating() {
return filmRating;
}
public void setFilmRating(String filmRating) {
this.filmRating = filmRating;
}
public int getFilmCategory() {
return filmCategory;
}
public void setFilmCategory(int filmCategory) {
this.filmCategory = filmCategory;
}
public ZonedDateTime getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(ZonedDateTime lastUpdate) {
this.lastUpdate = lastUpdate;
}
@ManyToOne
@JoinColumn(name = "language_id", referencedColumnName = "language_id", insertable=false, updatable = false)
private FilmLanguageModel filmLanguageModel;
public FilmLanguageModel getFilmLanguageModel() {
return filmLanguageModel;
}
@ManyToOne
@JoinColumn(name = "category_id", referencedColumnName = "category_id", insertable=false, updatable = false)
private FilmCategoryModel filmCategoryModel;
public FilmCategoryModel getFilmCategoryModel() {
return filmCategoryModel;
}
@OneToOne
@JoinColumn(name = "film_id", referencedColumnName = "film_id")
private FilmModel filmModel;
public FilmModel getFilmModel() {
return filmModel;
}
public void setFilmModel(FilmModel filmModel) {
this.filmModel = filmModel;
}
@Override
public String toString() {
return "FilmInfo{" +
"id=" + id +
", filmDescription=" + filmDescription + '\n' +
", releaseYear=" + releaseYear + ", filmLanguage=" + filmLanguage + '\n' +
", filmLength=" + filmLength + ", filmRating=" + filmRating + '\n' +
", filmCategory=" + filmCategory + '\n' + ", lastUpdate=" + lastUpdate + '}';
}
}

View File

@ -0,0 +1,49 @@
package org.example;
import jakarta.persistence.*;
import java.util.List;
@Entity
@Table(name="language")
public class FilmLanguageModel {
@Id
@GeneratedValue
@Column(name="language_id")
private int id;
@Column(name="language")
private String filmLanguage;
public FilmLanguageModel() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFilmLanguage() {
return filmLanguage;
}
public void setFilmLanguage(String filmLanguage) {
this.filmLanguage = filmLanguage;
}
@OneToMany(mappedBy = "filmLanguageModel", fetch = FetchType.LAZY)
private List<FilmInfoModel> filmInfoModel;
public FilmInfoModel getFilmInfo() {
return (FilmInfoModel) filmInfoModel;
}
@Override
public String toString() {
return "Language{" +
"id=" + id +
", filmLanguage='" + filmLanguage + '}';
}
}

View File

@ -0,0 +1,51 @@
package org.example;
import jakarta.persistence.*;
@Entity
@Table(name="films")
public class FilmModel {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="film_id")
private int id;
@Column(name="title")
private String filmTitle;
public FilmModel() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFilmTitle() {
return filmTitle;
}
public void setFilmTitle(String filmTitle) {
this.filmTitle = filmTitle;
}
@OneToOne(mappedBy = "filmModel", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private FilmInfoModel filmInfo;
public FilmInfoModel getFilmInfo() {
return filmInfo;
}
public void setFilmInfo(FilmInfoModel filmInfo) {
this.filmInfo = filmInfo;
}
@Override
public String toString() {
return "Film{" +
"id=" + id +
", filmTitle='" + filmTitle + '}';
}
}

View File

@ -1,116 +1,52 @@
package org.example; package org.example;
import model.*; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cfg.Configuration;
import java.io.IOException; import java.util.List;
import java.util.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Scanner;
/*
Klasa Main
*/
public class Main { public class Main {
public static void main(String[] args) throws IOException {
String API_key = "4c991761f17e10358c944a3c64a3e24c"; public static void main(String[] args) {
String fileCities = "cities.json"; System.out.println("Start");
// utworzenie listy miast wraz z ich koordynatami Configuration configuration = new Configuration();
JsonToMap jsonToMap = new JsonToMap(); configuration.configure("hibernate.cfg.xml");
Map<String, Map<String, Double>> cityMap =
jsonToMap.createCityMap(fileCities);
CityNames cityNames = new CityNames(); SessionFactory sessionFactory = configuration.buildSessionFactory();
cityNames.cityNamesRead(fileCities);
LocalDateTime czas = LocalDateTime.now(); try (Session session = sessionFactory.openSession()) {
Scanner scanner = new Scanner(System.in); Queries queries = new Queries(session);
// WYWOLANIE ZAPYTAN Z PARAMETRAMI
// queries.getFilmByLangYear("Japanese", "2006");
// queries.getFilmByLangCategory("Action", "Japanese");
// utworzenie pustego pliku tymczasowego przechowujacego wyniki zapytan // WYWOLANIE ZAPYTANIA STRONICOWANEGO
TemporaryFile temporaryFile = new TemporaryFile(); // queries.getAllFilmsByPage(4, session);
temporaryFile.createEmptyFile();
HttpClient httpClient = new HttpClient(); Transaction tx = null;
try {
tx = session.beginTransaction();
ForecastPreparation forecastPreparation = new ForecastPreparation(); //DODANIE DO BAZY NOWEGO REKORDU
System.out.println("Program rozpoczal dzialanie."); // FilmModel filmModel = queries.createFilmModel();
// session.save(filmModel);
tx.commit();
// glowna petla programu } catch (Exception e) {
while (true) { if (tx != null) {
tx.rollback();
System.out.println("Sprawdz pogode - y \n" +
"Zakoncz i zapisz wynik - z\n" +
"Wyjdz bez zapisywania - x");
String input = scanner.nextLine().toLowerCase();
// wyswietlenie prognozy dla wskazanego miasta
if (Objects.equals(input, "y")) {
System.out.println("Podaj nazwe miasta: ");
String inputCity = scanner.nextLine().toLowerCase();
if (cityMap.containsKey(inputCity)) {
Map<String, Double> specificCity = (Map<String, Double>) cityMap.get(inputCity);
double latitude = (double) specificCity.get("latitude");
double longitude = (double) specificCity.get("longitude");
// wygenerowanie odpowiedniego adresu url
String urlString = "https://api.openweathermap.org/data/2.5/weather?lat=" + latitude +
"&lon=" + longitude + "&appid=" + API_key;
String response = httpClient.executeGetRequest(urlString);
weatherForecast weatherForecast = forecastPreparation.fetchForecastData(inputCity, response);
String forecastString = weatherForecast.prepareForecastString();
System.out.println(forecastString);
// zapisanie prognozy do pliku tymczasowego
temporaryFile.addToFile(forecastString);
} else {
System.out.println("Podanego miasta nie ma na liscie.");
}
// zapis wynikow
} else if (Objects.equals(input, "z")) {
System.out.println("W jakim formacie chcesz zapisac wyniki?\n pdf/json/xml");
String whichFormat = scanner.nextLine().toLowerCase();
// odczyt czasu na potrzeby wygenerowania nazwy pliku
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmmss");
String sformatowanyCzas = czas.format(formatter);
// zapis do pdf
if (Objects.equals(whichFormat, "pdf")) {
String outputFile = "results/results" + sformatowanyCzas + ".pdf" ;
weatherForecast.saveToPdf(temporaryFile.FILE_NAME, outputFile);
//zapis do json
} else if (Objects.equals(whichFormat, "json")) {
String outputFile = "results/results" + sformatowanyCzas + ".json";
weatherForecast.saveToJson(outputFile);
// zapis do xml
} else if (Objects.equals(whichFormat, "xml")) {
String outputFile = "results/results" + sformatowanyCzas + ".xml";
weatherForecast.saveToXml(outputFile);
} else {
System.out.println("Wprowadz poprawna opcje.");
continue;
}
System.out.println("Program zakonczyl dzialanie.");
break;
// wyjscie z programu
} else if (Objects.equals(input,"x")) {
System.out.println("Program zakonczyl dzialanie.");
break;
} else {
System.out.println("Wprowadz poprawna opcje.");
} }
} }
} catch (Exception e) {
e.printStackTrace();
} finally {
sessionFactory.close();
} }
} }
}

View File

@ -0,0 +1,120 @@
package org.example;
import org.hibernate.Session;
import org.hibernate.query.Query;
import java.time.ZonedDateTime;
import java.util.List;
public class Queries {
Session session;
public Queries(Session session) {
this.session = session;
}
// ZAPYTANIE Z PARAMETREM
public List<Object[]> getFilmByLangYear(String language, String releaseYear) {
String hql = "SELECT f1.id, f2.filmTitle, f3.filmLanguage " +
"FROM FilmInfoModel f1 " +
"JOIN FilmModel f2 ON f1.id = f2.id " +
"JOIN FilmLanguageModel f3 ON f1.filmLanguage = f3.id " +
"WHERE f3.filmLanguage = :language AND f1.releaseYear = :releaseYear";
Query<Object[]> query = session.createQuery(hql, Object[].class)
.setParameter("language", language)
.setParameter("releaseYear", releaseYear);
List<Object[]> results = query.getResultList();
// wypisanie wynikow bezposrednio w konsoli
// for (Object[] result : results) {
//
// int filmId = (int) result[0];
// String filmTitle = (String) result[1];
// String filmLanguage = (String) result[2];
//
// System.out.println("Film ID: " + filmId);
// System.out.println("Film Title: " + filmTitle);
// System.out.println("Language: " + filmLanguage);
// System.out.println("-----------------------------------");
// }
return results;
}
// ZAPYTANIE Z PARAMETREM
public List<Object[]> getFilmByLangCategory(String categoryName, String languageName) {
String hql = "SELECT f1.id, f2.filmTitle, f3.filmLanguage, f4.filmCategory " +
"FROM FilmInfoModel f1 " +
"JOIN FilmModel f2 ON f1.id = f2.id " +
"JOIN FilmLanguageModel f3 ON f1.filmLanguage = f3.id " +
"JOIN FilmCategoryModel f4 ON f1.filmCategory = f4.id " +
"WHERE f3.filmLanguage = :language AND f4.filmCategory = :categoryName";
Query<Object[]> query = session.createQuery(hql, Object[].class)
.setParameter("categoryName", categoryName)
.setParameter("language", languageName);
List<Object[]> results = query.getResultList();
// wypisanie wynikow bezposrednio w konsoli
// for (Object[] result : results) {
//
// int filmId = (int) result[0];
// String filmTitle = (String) result[1];
// String filmCategory = (String) result[2];
// String filmLanguage = (String) result[3];
//
// System.out.println("Film ID: " + filmId);
// System.out.println("Film Title: " + filmTitle);
// System.out.println("Category: " + filmCategory);
// System.out.println("Film Language: " + filmLanguage);
// System.out.println("-----------------------------------");
// }
return results;
}
// ZAPYTANIE STRONICOWANE
public List<FilmModel> getAllFilmsByPage(int pageNumber, Session session) {
//calculate total number
Query queryTotal = session.createQuery("Select count(f) from FilmModel f");
long countResult = (long)queryTotal.getSingleResult();
Query<FilmModel> query = session.createQuery("Select f from FilmModel f");
// rozmiar i liczba stron
int pageSize = 10;
int pageTotal = (int) ((countResult / pageSize) + 1);
if (pageNumber > pageTotal) pageNumber = pageTotal;
query.setFirstResult((pageNumber - 1) * pageSize);
query.setMaxResults(pageSize);
return query.getResultList();
}
// DODANIE DO BAZY NOWEGO REKORDU
public static FilmModel createFilmModel() {
FilmModel filmModel = new FilmModel();
FilmInfoModel filmInfoModel = new FilmInfoModel();
filmModel.setFilmTitle("Test Film Title");
filmInfoModel.setFilmDescription("Test Movie Description");
filmInfoModel.setReleaseYear(2023);
filmInfoModel.setFilmLanguage(1);
filmInfoModel.setFilmLength(100);
filmInfoModel.setFilmRating("test");
filmInfoModel.setFilmCategory(1);
// Pole ZonedDateTime
ZonedDateTime currentTimestamp = ZonedDateTime.now();
filmInfoModel.setLastUpdate(currentTimestamp);
filmModel.setFilmInfo(filmInfoModel);
return filmModel;
}
}

View File

@ -0,0 +1,23 @@
<hibernate-configuration>
<session-factory>
<!-- ustawienia polaczenia z baza danych -->
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/PRA2024</property>
<property name="hibernate.connection.username">postgres</property>
<property name="hibernate.connection.password">password</property>
<!-- ustawienie domyslnej strefy czasowej -->
<property name="hibernate.jdbc.time_zone">Europe/Warsaw</property>
<!-- inne ustawienia Hibernate -->
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- skanowanie pakietow z encjami -->
<mapping class="org.example.FilmModel"/>
<mapping class="org.example.FilmInfoModel"/>
<mapping class="org.example.FilmLanguageModel"/>
<mapping class="org.example.FilmCategoryModel"/>
</session-factory>
</hibernate-configuration>

View File

@ -1,97 +0,0 @@
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
import model.HttpClient;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/*
Zgodnie z wymogami projektu - trzy testy mockujace przygotowane dla klasy HttpClient.
*/
public class HttpClientTest {
@Test
void testExecuteGetRequest() throws Exception {
// Dowolny adres URL
String urlString = "www.example.com";
// Przykladowy response
String expectedResponse = "{\"coord\":{\"lon\":44.34,\"lat\":10.99},\"weather\":" +
"[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\"" +
",\"icon\":\"04n\"}],\"base\":\"stations\",\"main\":{\"temp\":299.46,\"" +
"feels_like\":299.46,\"temp_min\":299.46,\"temp_max\":299.46,\"pressure\"" +
":1014,\"humidity\":66,\"sea_level\":1014,\"grnd_level\":1014},\"" +
"visibility\":10000,\"wind\":{\"speed\":4.89,\"deg\":78,\"gust\":5.26}," +
"\"clouds\":{\"all\":88},\"dt\":1701977972,\"sys\":{\"country\":\"SO\"," +
"\"sunrise\":1701918532,\"sunset\":1701959952},\"timezone\":10800,\"id\"" +
":54746,\"name\":\"Lughaye\",\"cod\":200}\n";
// Przygotowanie mockow
CloseableHttpClient mockHttpClient = Mockito.mock(CloseableHttpClient.class);
org.apache.http.HttpEntity mockEntity = Mockito.mock(org.apache.http.HttpEntity.class);
CloseableHttpResponse mockResponse = Mockito.mock(CloseableHttpResponse.class);
when(mockResponse.getEntity()).thenReturn(mockEntity);
when(mockEntity.getContent()).thenReturn(new ByteArrayInputStream(expectedResponse.getBytes(StandardCharsets.UTF_8)));
when(mockEntity.getContentLength()).thenReturn((long) expectedResponse.length());
// Przygotowujemy odpowiedź do zwrócenia przez mock
when(mockHttpClient.execute(any(HttpGet.class))).thenReturn(mockResponse);
// Instancja testowanej klasy z przekazaniem zmockowanego klienta
HttpClient httpClient = new HttpClient(mockHttpClient);
// Act & Assert
String result = httpClient.executeGetRequest(urlString);
assertEquals(expectedResponse, result);
}
@Test
void testExecuteGetRequest_EmptyResponse() throws IOException {
// Dowolny adres url
String urlString = "www.example.com";
// Przygotowanie mockow
CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class);
CloseableHttpResponse mockHttpResponse = mock(CloseableHttpResponse.class);
when(mockHttpClient.execute(ArgumentMatchers.any(HttpGet.class))).thenReturn(mockHttpResponse);
when(mockHttpResponse.getEntity()).thenReturn(null);
// Instancja testowanej klasy z przekazaniem zmockowanego klienta
HttpClient httpClient = new HttpClient(mockHttpClient);
// Act & Assert
String result = httpClient.executeGetRequest(urlString);
assertEquals("", result);
}
@Test
void testExecuteGetRequest_ClientProtocolException() throws IOException {
// Przygotowanie mockow
CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class);
when(mockHttpClient.execute(ArgumentMatchers.any(HttpGet.class))).thenThrow(new ClientProtocolException("Mocked ClientProtocolException"));
// Instancja testowanej klasy z przekazaniem zmockowanego klienta
HttpClient httpClient = new HttpClient(mockHttpClient);
// Act & Assert
RuntimeException runtimeException = assertThrows(RuntimeException.class, () ->
httpClient.executeGetRequest("http://example.com")
);
assertEquals("org.apache.http.client.ClientProtocolException: Mocked ClientProtocolException", runtimeException.getMessage());
}
}

View File

@ -0,0 +1,184 @@
package org.example;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class QueriesTest {
private FilmModel createFilm(String title) {
FilmModel film = new FilmModel();
film.setFilmTitle(title);
return film;
}
// ZAPYTANIE ZA PARAMETREM
@Test
public void testGetFilmByLangYearWithResults() {
// Ustawienie danych testowych
Session mockSession = mock(Session.class);
Query<Object[]> mockQuery = mock(Query.class);
List<Object[]> expectedResults = Arrays.asList(
new Object[]{1, "Film1", "English"},
new Object[]{2, "Film2", "Spanish"}
);
when(mockSession.createQuery(anyString(), eq(Object[].class))).thenReturn(mockQuery);
when(mockQuery.setParameter("language", "English")).thenReturn(mockQuery);
when(mockQuery.setParameter("releaseYear", "2022")).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(expectedResults);
Queries queries = new Queries(mockSession);
List<Object[]> result = queries.getFilmByLangYear("English", "2022");
assertEquals(expectedResults, result);
}
@Test
public void testGetAllFilmsByPage() {
Session mockSession = mock(Session.class);
Query mockQueryTotal = mock(Query.class);
Query mockQuery = mock(Query.class);
long totalCount = 3;
when(mockSession.createQuery("Select count(f) from FilmModel f")).thenReturn(mockQueryTotal);
when(mockQueryTotal.getSingleResult()).thenReturn(totalCount);
List<FilmModel> filmList = Arrays.asList(
createFilm("Test1"),
createFilm("Test2"),
createFilm("Test3")
);
when(mockSession.createQuery("Select f from FilmModel f")).thenReturn(mockQuery);
when(mockQuery.setFirstResult(anyInt())).thenReturn(mockQuery);
when(mockQuery.setMaxResults(anyInt())).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(filmList);
Queries queries = new Queries(mockSession);
List<FilmModel> result = queries.getAllFilmsByPage(1, mockSession);
assertEquals(filmList, result);
verify(mockQueryTotal).getSingleResult();
verify(mockQuery).setFirstResult(0);
verify(mockQuery).setMaxResults(10);
}
// ZAPYTANIE Z PARAMETREM
@Test
public void testGetFilmByLangCategoryWithResults() {
Session mockSession = mock(Session.class);
Query<Object[]> mockQuery = mock(Query.class);
List<Object[]> expectedResults = Arrays.asList(
new Object[]{1, "Film1", "English", "Action"},
new Object[]{2, "Film2", "Spanish", "Drama"}
);
when(mockSession.createQuery(anyString(), eq(Object[].class))).thenReturn(mockQuery);
when(mockQuery.setParameter("categoryName", "Action")).thenReturn(mockQuery);
when(mockQuery.setParameter("language", "English")).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(expectedResults);
Queries queries = new Queries(mockSession);
List<Object[]> result = queries.getFilmByLangCategory("Action", "English");
assertEquals(expectedResults, result);
}
@Test
public void testGetFilmByLangCategoryWithoutResults() {
Session mockSession = mock(Session.class);
Query<Object[]> mockQuery = mock(Query.class);
List<Object[]> expectedResults = Collections.emptyList(); // Brak wynikow
when(mockSession.createQuery(anyString(), eq(Object[].class))).thenReturn(mockQuery);
when(mockQuery.setParameter("categoryName", "Comedy")).thenReturn(mockQuery);
when(mockQuery.setParameter("language", "French")).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(expectedResults);
Queries queries = new Queries(mockSession);
List<Object[]> result = queries.getFilmByLangCategory("Comedy", "French");
assertTrue(result.isEmpty());
}
// ZAPYTANIE STRONICOWANE
@Test
public void testGetFilmByLangYearWithoutResults() {
Session mockSession = mock(Session.class);
Query<Object[]> mockQuery = mock(Query.class);
List<Object[]> expectedResults = Collections.emptyList(); // Brak wynikow
when(mockSession.createQuery(anyString(), eq(Object[].class))).thenReturn(mockQuery);
when(mockQuery.setParameter("language", "French")).thenReturn(mockQuery);
when(mockQuery.setParameter("releaseYear", "2022")).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(expectedResults);
Queries queries = new Queries(mockSession);
List<Object[]> result = queries.getFilmByLangYear("French", "2022");
assertTrue(result.isEmpty());
}
@Test
public void testGetAllFilmsByPageWhenNoFilms() {
Session mockSession = mock(Session.class);
Query mockQueryTotal = mock(Query.class);
Query mockQuery = mock(Query.class);
long totalCount = 0;
when(mockSession.createQuery("Select count(f) from FilmModel f")).thenReturn(mockQueryTotal);
when(mockQueryTotal.getSingleResult()).thenReturn(totalCount);
List<FilmModel> filmList = Arrays.asList(); // pusta lista filmów
when(mockSession.createQuery("Select f from FilmModel f")).thenReturn(mockQuery);
when(mockQuery.getResultList()).thenReturn(filmList);
Queries queries = new Queries(mockSession);
List<FilmModel> result = queries.getAllFilmsByPage(1, mockSession);
assertEquals(filmList, result);
verify(mockQueryTotal).getSingleResult();
}
// SPRAWDZENIE CZY UTWORZONY OBIEKT ZAWIERA DANE ZGODNE ZE WSTEPNIE WPROWADZONYMI W DEFINICJI METODY
@Test
public void testCreateFilmModelWithExpectedData() {
Session mockSession = mock(Session.class);
Queries queries = new Queries(mockSession);
FilmModel filmModel = queries.createFilmModel();
// Sprawdzenie, czy utworzony obiekt zawiera oczekiwane dane
assertNotNull(filmModel);
assertEquals("Test Film Title", filmModel.getFilmTitle());
FilmInfoModel filmInfoModel = filmModel.getFilmInfo();
assertNotNull(filmInfoModel);
assertEquals("Test Movie Description", filmInfoModel.getFilmDescription());
assertEquals(2023, filmInfoModel.getReleaseYear());
assertEquals(1, filmInfoModel.getFilmLanguage());
assertEquals(100, filmInfoModel.getFilmLength());
assertEquals("test", filmInfoModel.getFilmRating());
assertEquals(1, filmInfoModel.getFilmCategory());
ZonedDateTime currentTimestamp = ZonedDateTime.now();
ZonedDateTime filmInfoTimestamp = filmInfoModel.getLastUpdate();
// Test timestampow z pozostawieniem pewnej tolerancji czasowej
assertTrue(filmInfoTimestamp.isBefore(currentTimestamp.plusSeconds(5)) &&
filmInfoTimestamp.isAfter(currentTimestamp.minusSeconds(5)));
}
}

24
temporary_file.txt Normal file
View File

@ -0,0 +1,24 @@
city: berlin
description: scattered clouds
temperature[K]: 282,63
pressure[hPa]: 978
humidity[%]: 83
--------------------
city: berlin
description: scattered clouds
temperature[K]: 282,63
pressure[hPa]: 978
humidity[%]: 83
--------------------
city: warsaw
description: broken clouds
temperature[K]: 279,29
pressure[hPa]: 989
humidity[%]: 92
--------------------
city: warsaw
description: broken clouds
temperature[K]: 279,29
pressure[hPa]: 989
humidity[%]: 92
--------------------