commit 2486e64be289db044ba25dd1990a42e58b600ea8 Author: Adam Gulczyński Date: Fri Dec 15 23:51:44 2023 +0100 final commit project v1 diff --git a/.env b/.env new file mode 100644 index 0000000..50cbe1c --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +API_KEY=620e5e3fe298cdf4c0e435e2c8f4eb8e +BASE_PATH=/Users/adamgulczynski/IdeaProjects/project1/src/main/java/org/adamgulczynski/ \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..09c9fec --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +API_KEY= +BASE_PATH= \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f68d109 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/aws.xml b/.idea/aws.xml new file mode 100644 index 0000000..2c4ea32 --- /dev/null +++ b/.idea/aws.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..38438f7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..fd9de1c --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,64 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..5bded3b --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..aacacf5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9fd9198 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Java pracownia project 1 + +### Działanie programu: +Po uruchomieniu programu, w konsoli należy wybrac jedno z miast (wielkość liter nie ma znaczenie) +Dane dotyczace miast znajduja sie w pliku `data.json` + +Informacje w konsoli sa wuyswietlane po kolei i przy każdym etapie prosza o konkretna czynnosc. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e07880d --- /dev/null +++ b/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.adamgulczynski + project1 + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + com.e-iceblue + e-iceblue + https://repo.e-iceblue.com/nexus/content/groups/public/ + + + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.0 + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.13.0 + + + + io.github.cdimascio + dotenv-java + 3.0.0 + + + + org.json + json + 20230227 + + + + org.apache.pdfbox + pdfbox + 3.0.1 + + + + e-iceblue + spire.pdf + 9.12.0 + + + + org.mockito + mockito-core + 3.12.4 + test + + + + junit + junit + 4.13.2 + test + + + + com.lowagie + itext + 2.1.7 + + + + + \ No newline at end of file diff --git a/src/main/java/org/adamgulczynski/DataFetcher.java b/src/main/java/org/adamgulczynski/DataFetcher.java new file mode 100644 index 0000000..bf4f14e --- /dev/null +++ b/src/main/java/org/adamgulczynski/DataFetcher.java @@ -0,0 +1,52 @@ +package org.adamgulczynski; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class DataFetcher { + private final String apiKey; + + public DataFetcher(String apiKey) { + this.apiKey = apiKey; + } + + public String fetchWeather(double latitude, double longitude) throws IllegalArgumentException { + + if (latitude > 90 || latitude < -90) { + throw new IllegalArgumentException(); + } else if (longitude > 180 || longitude < -180) { + throw new IllegalArgumentException(); + } + + String urlStr = "https://api.openweathermap.org/data/2.5/weather?lat=" + + latitude + "&lon=" + longitude + "&appid=" + this.apiKey; + + try { + URL url = new URL(urlStr); + + // Open a connection to the URL + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + // Set the request method to GET + connection.setRequestMethod("GET"); + + // Read the response from the server + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + String line; + StringBuilder response = new StringBuilder(); + + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + return response.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/src/main/java/org/adamgulczynski/JsonReader.java b/src/main/java/org/adamgulczynski/JsonReader.java new file mode 100644 index 0000000..61b3c38 --- /dev/null +++ b/src/main/java/org/adamgulczynski/JsonReader.java @@ -0,0 +1,54 @@ +package org.adamgulczynski; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JsonReader { + private Map> dataMap; + + public Map> readFile(String filePath) { + // Create a map to store the data + Map> cityDataMap = new HashMap<>(); + + try { + // Create ObjectMapper + ObjectMapper objectMapper = new ObjectMapper(); + + // Read JSON array from file into JsonNode + JsonNode jsonArray = objectMapper.readTree(new File(filePath)); + + for (JsonNode jsonNode : jsonArray) { + String city = jsonNode.get("city").asText(); + double lat = jsonNode.get("lat").asDouble(); + double lon = jsonNode.get("lon").asDouble(); + + // Create a map for latitude and longitude + Map latLngMap = new HashMap<>(); + latLngMap.put("latitude", lat); + latLngMap.put("longitude", lon); + + // Put the data into the main map + cityDataMap.put(city, latLngMap); + } + this.dataMap = cityDataMap; + } catch (IOException e) { + e.printStackTrace(); + } + return cityDataMap; + } + + public void printEntries() { + short index = 1; + Set keys = this.dataMap.keySet(); + for (String key : keys) { + System.out.println(index + ". " + key); + index++; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/adamgulczynski/Main.java b/src/main/java/org/adamgulczynski/Main.java new file mode 100644 index 0000000..db59259 --- /dev/null +++ b/src/main/java/org/adamgulczynski/Main.java @@ -0,0 +1,97 @@ +package org.adamgulczynski; + +import java.util.*; + +import io.github.cdimascio.dotenv.Dotenv; + +public class Main { + + public static void main(String[] args) { + + // get env variables + Dotenv dotenv = Dotenv.load(); + String basePath = dotenv.get("BASE_PATH"); + String apiKey = dotenv.get("API_KEY"); + + // read city details from json file + JsonReader readJSON = new JsonReader(); + Map> cityDataMap = readJSON.readFile(basePath + "data.json"); + + // print available cities + System.out.println("Dostepne miasta:"); + readJSON.printEntries(); + + DataFetcher dataFetcher = new DataFetcher(apiKey); + + Scanner scanner = new Scanner(System.in); + + List weatherDataList = new ArrayList<>(); + + while (true) { + System.out.print("P-Podaj miasto, Z-Zakoncz: "); + String userInput = scanner.nextLine(); + + if (Objects.equals(userInput, "P") || Objects.equals(userInput, "p")) { + String chosenCity = scanner.nextLine().toLowerCase(); + Map chosenCityData = (Map) cityDataMap.get(chosenCity); + if (cityDataMap.containsKey(chosenCity)) { + double latitude = (double) chosenCityData.get("latitude"); + double longitude = (double) chosenCityData.get("longitude"); + + String weatherDataString; + try { + weatherDataString = dataFetcher.fetchWeather(latitude, longitude); + } catch (IllegalArgumentException e) { + System.out.println("Niepoprawne dane w pliku json"); + continue; + } + + System.out.println(weatherDataString); + + // convert to WeatherData object + WeatherData weatherData = WeatherParser.parseWeatherToWeatherData(weatherDataString); + + // display the data + System.out.println(weatherData); + + // add data to a list, will be written to the file + weatherDataList.add(weatherData); + } else { + System.out.println("Nie ma takiego miasta."); + } + } else if (Objects.equals(userInput, "Z") || Objects.equals(userInput, "z")) { + label: + while (true) { + System.out.println("Do jakiego pliku chcesz zapisac dane? xml/json/pdf"); + String userChoice = scanner.nextLine().toLowerCase(); + + String path = basePath + "weather"; + + switch (userChoice) { + case "xml": + WeatherData.writeToXmlFile(path, weatherDataList); + break label; + case "json": + WeatherData.writeToJsonFile(path, weatherDataList); + break label; + case "pdf": + WeatherData.writeToPdfFile(path, weatherDataList); + break label; + default: + System.out.println("Bledny format."); + break; + } + + } + + break; + } else { + System.out.println("Bledna wartosc, podaj 'P' lub 'Z'"); + } + } + + scanner.close(); + + } + +} \ No newline at end of file diff --git a/src/main/java/org/adamgulczynski/WeatherData.java b/src/main/java/org/adamgulczynski/WeatherData.java new file mode 100644 index 0000000..e28be1e --- /dev/null +++ b/src/main/java/org/adamgulczynski/WeatherData.java @@ -0,0 +1,153 @@ +package org.adamgulczynski; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import java.io.*; + +import com.lowagie.text.*; +import com.lowagie.text.pdf.*; + +import java.util.List; + +public class WeatherData { + @JsonProperty("miasto") + private final String city; + + @JsonProperty("temperatura") + private final double temperature; + + @JsonProperty("wilgotnosc") + private final int humidity; + + @JsonProperty("wiatr") + private final double windSpeed; + + @JsonProperty("zachmurzenie") + private final int clouds; + + @JsonProperty("cisnienie") + private final int pressure; + + public WeatherData(String city, double temperature, int humidity, double windSpeed, int clouds, int pressure) { + this.city = city; + this.temperature = temperature; + this.humidity = humidity; + this.windSpeed = windSpeed; + this.clouds = clouds; + this.pressure = pressure; + } + + @Override + public String toString() { + return "Miasto: " + city + '\n' + + "Temperatura: " + temperature + " K\n" + + "Cisnienie: " + pressure + " hPa\n" + + "Wilgotnosc: " + humidity + "%\n" + + "Wiatr: " + windSpeed + " m/s\n" + + "Zachmurzenie: " + clouds + " %\n\n"; + } + + public String getCity() { + return city; + } + + public double getTemperature() { + return temperature; + } + + public int getHumidity() { + return humidity; + } + + public double getWindSpeed() { + return windSpeed; + } + + public int getClouds() { + return clouds; + } + + public int getPressure() { + return pressure; + } + + public static void writeToJsonFile(String filePath, List weatherDataList) { + ObjectMapper objectMapper = new ObjectMapper(); + + String path = filePath + ".json"; + try { + File file = new File(path); + ObjectWriter objectWriter = objectMapper.writer(new DefaultPrettyPrinter()); + objectWriter.writeValue(file, weatherDataList); + + System.out.println("Dane zapisane do: " + path); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void writeToXmlFile(String filePath, List weatherDataList) { + XmlMapper xmlMapper = new XmlMapper(); + + String path = filePath + ".xml"; + try { + File file = new File(path); + ObjectWriter objectWriter = xmlMapper.writerWithDefaultPrettyPrinter(); + objectWriter.writeValue(file, weatherDataList); + + System.out.println("Dane zapisane do: " + path); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void writeToTxtFile(String filePath, List weatherDataList) { + StringBuilder content = new StringBuilder(); + for (WeatherData data : weatherDataList) { + content.append(data.toString()); + } + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath + ".txt"))) { + writer.write(content.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void writeToPdfFile(String filePath, List weatherDataList) { + // create .txt file + writeToTxtFile(filePath, weatherDataList); + + BufferedReader input = null; + Document output = null; + try { + input = new BufferedReader(new FileReader(filePath + ".txt")); + output = new Document(PageSize.LETTER, 40, 40, 40, 40); + + filePath = filePath + ".pdf"; + PdfWriter.getInstance(output, new FileOutputStream(filePath)); + + output.open(); + output.addAuthor("Adam Gulczynski"); + output.addSubject("Projekt"); + output.addTitle("Projekt"); + + String line = ""; + while (null != (line = input.readLine())) { + System.out.println(line); + Paragraph p = new Paragraph(line); + p.setAlignment(Element.ALIGN_JUSTIFIED); + output.add(p); + } + System.out.println("Dane zapisane do: " + filePath); + output.close(); + input.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/adamgulczynski/WeatherParser.java b/src/main/java/org/adamgulczynski/WeatherParser.java new file mode 100644 index 0000000..f05621e --- /dev/null +++ b/src/main/java/org/adamgulczynski/WeatherParser.java @@ -0,0 +1,20 @@ +package org.adamgulczynski; + +import org.json.JSONObject; + +public class WeatherParser { + + public static WeatherData parseWeatherToWeatherData(String response) { + + JSONObject jsonObject = new JSONObject(response); + + String city = jsonObject.getString("name"); + double temperature = jsonObject.getJSONObject("main").getDouble("temp"); + int humidity = jsonObject.getJSONObject("main").getInt("humidity"); + double windSpeed = jsonObject.getJSONObject("wind").getDouble("speed"); + int clouds = jsonObject.getJSONObject("clouds").getInt("all"); + int pressure = jsonObject.getJSONObject("main").getInt("pressure"); + + return new WeatherData(city, temperature, humidity, windSpeed, clouds, pressure); + } +} diff --git a/src/main/java/org/adamgulczynski/data.json b/src/main/java/org/adamgulczynski/data.json new file mode 100644 index 0000000..8e5a885 --- /dev/null +++ b/src/main/java/org/adamgulczynski/data.json @@ -0,0 +1,37 @@ +[ + { + "city": "warsaw", + "lat": 52.2297, + "lon": 21.0122 + }, + { + "city": "london", + "lat": 51.5072, + "lon": 0.1276 + }, + { + "city": "poznan", + "lat": 52.41, + "lon": 16.93 + }, + { + "city": "berlin", + "lat": 52.52, + "lon": 13.41 + }, + { + "city": "barcelona", + "lat": 41.39, + "lon": 2.17 + }, + { + "city": "paris", + "lat": 48.86, + "lon": 2.35 + }, + { + "city": "stockholm", + "lat": 59.33, + "lon": 18.07 + } +] diff --git a/src/test/java/WeatherDataTest.java b/src/test/java/WeatherDataTest.java new file mode 100644 index 0000000..129887c --- /dev/null +++ b/src/test/java/WeatherDataTest.java @@ -0,0 +1,110 @@ +import org.adamgulczynski.DataFetcher; +import org.adamgulczynski.WeatherData; +import org.adamgulczynski.WeatherParser; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +class WeatherDataTest { + + @Test + void testWeatherRequestWithGoodCoordinates() throws IOException { + String sampleBody = """ + { + "name": "london", + "main": { + "temp": 280.95, + "humidity": 79, + "pressure": 1038 + }, + "wind": { + "speed": 4.12 + }, + "clouds": { + "all": 100 + } + } + """; + + DataFetcher mockDataFetcher = mock(DataFetcher.class); + + double lat = 12.2; + double lon = 22.3; + when(mockDataFetcher.fetchWeather(lat, lon)) + .thenReturn(sampleBody); + + WeatherData weatherData = WeatherParser.parseWeatherToWeatherData(mockDataFetcher.fetchWeather(lat, lon)); + + assertEquals(weatherData.getTemperature(), 280.95); + assertEquals(weatherData.getHumidity(), 79); + assertEquals(weatherData.getWindSpeed(), 4.12); + assertEquals(weatherData.getPressure(), 1038); + assertEquals(weatherData.getClouds(), 100); + } + + @Test + void testWeatherRequestWithValidCoordinates() throws IOException { + String sampleBody = """ + { + "name": "london", + "main": { + "temp": 280.95, + "humidity": 79, + "pressure": 1038 + }, + "wind": { + "speed": 4.12 + }, + "clouds": { + "all": 100 + } + } + """; + + DataFetcher mockDataFetcher = mock(DataFetcher.class); + + double lat = 12.2; + double lon = 22.3; + when(mockDataFetcher.fetchWeather(lat, lon)) + .thenReturn(sampleBody); + + WeatherData weatherData = WeatherParser.parseWeatherToWeatherData(mockDataFetcher.fetchWeather(lat, lon)); + + assertEquals(weatherData.getTemperature(), 280.95); + assertEquals(weatherData.getHumidity(), 79); + assertEquals(weatherData.getWindSpeed(), 4.12); + assertEquals(weatherData.getPressure(), 1038); + assertEquals(weatherData.getClouds(), 100); + } + + @Test + void testWeatherRequestWithInvalidLatitude() { + DataFetcher mockDataFetcher = new DataFetcher("tes"); + + // Using invalid coordinates + double invalidLat = 500.0; + double validLon = 22.3; + + assertThrows(IllegalArgumentException.class, () -> { + mockDataFetcher.fetchWeather(invalidLat, validLon); + }); + } + + @Test + void testWeatherRequestWithInvalidLongitude() { + DataFetcher mockDataFetcher = new DataFetcher("tes"); + + // Using invalid coordinates + double validLat = 20.0; + double invalidLon = 522.3; + + assertThrows(IllegalArgumentException.class, () -> { + mockDataFetcher.fetchWeather(validLat, invalidLon); + }); + } +} \ No newline at end of file diff --git a/target/classes/org/adamgulczynski/DataFetcher.class b/target/classes/org/adamgulczynski/DataFetcher.class new file mode 100644 index 0000000..eecb574 Binary files /dev/null and b/target/classes/org/adamgulczynski/DataFetcher.class differ diff --git a/target/classes/org/adamgulczynski/JsonReader.class b/target/classes/org/adamgulczynski/JsonReader.class new file mode 100644 index 0000000..d06d8bc Binary files /dev/null and b/target/classes/org/adamgulczynski/JsonReader.class differ diff --git a/target/classes/org/adamgulczynski/Main.class b/target/classes/org/adamgulczynski/Main.class new file mode 100644 index 0000000..7a066c2 Binary files /dev/null and b/target/classes/org/adamgulczynski/Main.class differ diff --git a/target/classes/org/adamgulczynski/WeatherData.class b/target/classes/org/adamgulczynski/WeatherData.class new file mode 100644 index 0000000..080b813 Binary files /dev/null and b/target/classes/org/adamgulczynski/WeatherData.class differ diff --git a/target/classes/org/adamgulczynski/WeatherParser.class b/target/classes/org/adamgulczynski/WeatherParser.class new file mode 100644 index 0000000..3ed0982 Binary files /dev/null and b/target/classes/org/adamgulczynski/WeatherParser.class differ diff --git a/target/test-classes/DataFetcherTest.class b/target/test-classes/DataFetcherTest.class new file mode 100644 index 0000000..6475d1b Binary files /dev/null and b/target/test-classes/DataFetcherTest.class differ diff --git a/target/test-classes/WeatherDataTest.class b/target/test-classes/WeatherDataTest.class new file mode 100644 index 0000000..03cb0e0 Binary files /dev/null and b/target/test-classes/WeatherDataTest.class differ