The report should include the project's background and motivation and a brief overview of related and similar work, with at least 3 references. This formal report will be a culmination of previous reports submitted and should include a detailed description of the implemented system, including what it does, how it works, and how it is used. The report should address all the feedback provided in previous submissions. The report should also detail the group’s accomplishments and reflect on their experience.  

 

Final Report Outline: 

  • Introduction – Brief summary of your project, context and motivation  
  • Process Overview – brief description of your approach, tools and artifacts used, including summary of individual contributions 
  • Requirements Specification – summary of functional and non-functional requirements 
  • Project Design – architecture and implementation of your project and how it works 
  • Project Evaluation: Testing strategy, Test Plan and Results, Validation  
  • Design and Alternate Designs – changes made to the source code due to testing results 
  • Development History: Project timeline 
  • Discussion: Lessons learned, design strengths, limitations and suggestions for future improvement 
  • Conclusion 
  • Acknowledgement (optional) 
  • References 
  • Appendix 
    • System specification: technical specifications, minimum hardware requirements of the project implemented 
    • User Guide 
    • Other appendices (optional) 

Guidelines for the format and submission of the paper are as follows: 

  • The paper should be 15-20 pages in length. (This minimum and maximum length should not include the title page, appendix, separate figures and tables, or the list of references); 
  • The paper should include a cover page containing the project's title and the names of project team members. All team members should submit the same document to the assignment submission area. 
  • Careful attention should be given to source citations, and a proper listing of references. 
  • The paper should be well formatted and well organized with proper formatting of all graphs, images, tables etc. 

weather_app/pom.xml

4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.1 com.service weather 0.0.1-SNAPSHOT weather Weather website 17 org.springframework.boot spring-boot-starter-web com.h2database h2 runtime org.springframework.boot spring-boot-starter-test test jakarta.persistence jakarta.persistence-api 3.1.0 org.mockito mockito-core test org.mockito mockito-junit-jupiter test org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-maven-plugin

weather_app/src/main/java/com/service/weather/controller/WeatherController.java

weather_app/src/main/java/com/service/weather/controller/WeatherController.java

package  com . service . weather . controller ;

import  com . service . weather . model . WeatherRecord ;
import  com . service . weather . service . WeatherService ;
import  org . springframework . beans . factory . annotation . Autowired ;
import  org . springframework . web . bind . annotation . * ;

/**
 * The WeatherController class handles HTTP requests related to weather data.
 * It provides an endpoint to fetch weather information based on a given zip code.
 */
@ RestController
@ RequestMapping ( "/api/weather" )
public   class   WeatherController   {

    @ Autowired
     private   WeatherService  weatherService ;

    @ GetMapping
     public   WeatherRecord  getWeatherByZipCode ( @ RequestParam   String  zipCode )   {
         return  weatherService . getWeatherByZipCode ( zipCode );
     }

}

weather_app/src/main/java/com/service/weather/controller/ZipCodeController.java

weather_app/src/main/java/com/service/weather/controller/ZipCodeController.java

package  com . service . weather . controller ;

import  com . service . weather . model . ZipCode ;
import  com . service . weather . service . ZipCodeService ;
import  org . springframework . beans . factory . annotation . Autowired ;
import  org . springframework . web . bind . annotation . * ;

import  java . util . List ;

/**
 * The ZipCodeController class handles HTTP requests related to zip codes.
 * It provides endpoints to fetch all zip codes, add a new zip code, and remove an existing zip code.
 */
@ RestController
@ RequestMapping ( "/api/zipcodes" )
public   class   ZipCodeController   {

    @ Autowired
     private   ZipCodeService  zipCodeService ;

    @ GetMapping
     public   List < ZipCode >  getAllZipCodes ()   {
         return  zipCodeService . getAllZipCodes ();
     }

    @ PostMapping
     public   ZipCode  addZipCode ( @ RequestBody   ZipCode  zipCode )   {
         return  zipCodeService . addZipCode ( zipCode );
     }

    @ DeleteMapping ( "/{id}" )
     public   void  removeZipCode ( @ PathVariable   Long  id )   {
        zipCodeService . removeZipCode ( id );
     }
}

weather_app/src/main/java/com/service/weather/model/OpenWeatherMapResponse.java

weather_app/src/main/java/com/service/weather/model/OpenWeatherMapResponse.java

package  com . service . weather . model ;

import  com . fasterxml . jackson . annotation . JsonIgnoreProperties ;
import  com . fasterxml . jackson . annotation . JsonProperty ;

import  java . util . List ;

/**
 * The OpenWeatherMapResponse class represents the response structure from the OpenWeatherMap API.
 */
@ JsonIgnoreProperties ( ignoreUnknown  =   true )
public   class   OpenWeatherMapResponse   {

     private   Main  main ;
     private   Wind  wind ;
     private   List < Weather >  weather ;
     private   String  name ;

     public   Main  getMain ()   {
         return  main ;
     }

     public   void  setMain ( Main  main )   {
         this . main  =  main ;
     }

     public   Wind  getWind ()   {
         return  wind ;
     }

     public   void  setWind ( Wind  wind )   {
         this . wind  =  wind ;
     }

     public   List < Weather >  getWeather ()   {
         return  weather ;
     }

     public   void  setWeather ( List < Weather >  weather )   {
         this . weather  =  weather ;
     }

     public   String  getName ()   {
         return  name ;
     }

     public   void  setName ( String  name )   {
         this . name  =  name ;
     }

    @ JsonIgnoreProperties ( ignoreUnknown  =   true )
     public   static   class   Main   {
         private   double  temp ;
        @ JsonProperty ( "feels_like" )
         private   double  feels_like ;
         private   double  temp_min ;
         private   double  temp_max ;
         private   int  humidity ;

         public   double  getTemp ()   {
             return  temp ;
         }

         public   void  setTemp ( double  temp )   {
             this . temp  =  temp ;
         }

         public   double  getFeels_like ()   {
             return  feels_like ;
         }

         public   void  setFeels_like ( double  feelsLike )   {
             this . feels_like  =  feelsLike ;
         }

         public   double  getTemp_min ()   {
             return  temp_min ;
         }

         public   void  setTemp_min ( double  temp_min )   {
             this . temp_min  =  temp_min ;
         }

         public   double  getTemp_max ()   {
             return  temp_max ;
         }

         public   void  setTemp_max ( double  temp_max )   {
             this . temp_max  =  temp_max ;
         }

         public   int  getHumidity ()   {
             return  humidity ;
         }

         public   void  setHumidity ( int  humidity )   {
             this . humidity  =  humidity ;
         }
     }

    @ JsonIgnoreProperties ( ignoreUnknown  =   true )
     public   static   class   Wind   {
         private   double  speed ;

         // Getters and setters

         public   double  getSpeed ()   {
             return  speed ;
         }

         public   void  setSpeed ( double  speed )   {
             this . speed  =  speed ;
         }
     }

    @ JsonIgnoreProperties ( ignoreUnknown  =   true )
     public   static   class   Weather   {
         private   int  id ;
         private   String  icon ;

         // Getters and setters

         public   int  getId ()   {
             return  id ;
         }

         public   void  setId ( int  id )   {
             this . id  =  id ;
         }

         public   String  getIcon ()   {
             return  icon ;
         }

         public   void  setIcon ( String  icon )   {
             this . icon  =  icon ;
         }
     }
}

weather_app/src/main/java/com/service/weather/model/WeatherRecord.java

weather_app/src/main/java/com/service/weather/model/WeatherRecord.java

package  com . service . weather . model ;

import  jakarta . persistence . Entity ;
import  jakarta . persistence . GeneratedValue ;
import  jakarta . persistence . GenerationType ;
import  jakarta . persistence . Id ;

/**
 * The WeatherRecord class represents a record of weather data.
 */
@ Entity
public   class   WeatherRecord   {

    @ Id
    @ GeneratedValue ( strategy  =   GenerationType . AUTO )
     private   Long  id ;
     private   String  zipCode ;
     private   double  temperature ;
     private   double  feelsLike ;
     private   double  tempMin ;
     private   double  tempMax ;
     private   int  humidity ;
     private   double  windSpeed ;
     private   String  city ;
     private   String  icon ;
     private   int  conditionCode ;

     public   WeatherRecord ()   {}

     public   WeatherRecord ( String  zipCode ,   double  temperature ,   double  feelsLike ,   double  tempMin ,   double  tempMax ,   int  humidity ,   double  windSpeed ,   String  city ,   String  icon ,   int  conditionCode )   {
         this . zipCode  =  zipCode ;
         this . temperature  =  temperature ;
         this . feelsLike  =  feelsLike ;
         this . tempMin  =  tempMin ;
         this . tempMax  =  tempMax ;
         this . humidity  =  humidity ;
         this . windSpeed  =  windSpeed ;
         this . city  =  city ;
         this . icon  =  icon ;
         this . conditionCode  =  conditionCode ;
     }

     public   Long  getId ()   {
         return  id ;
     }

     public   void  setId ( Long  id )   {
         this . id  =  id ;
     }

     public   String  getZipCode ()   {
         return  zipCode ;
     }

     public   void  setZipCode ( String  zipCode )   {
         this . zipCode  =  zipCode ;
     }

     public   double  getTemperature ()   {
         return  temperature ;
     }

     public   void  setTemperature ( double  temperature )   {
         this . temperature  =  temperature ;
     }

     public   double  getFeelsLike ()   {
         return  feelsLike ;
     }

     public   void  setFeelsLike ( double  feelsLike )   {
         this . feelsLike  =  feelsLike ;
     }

     public   double  getTempMin ()   {
         return  tempMin ;
     }

     public   void  setTempMin ( double  tempMin )   {
         this . tempMin  =  tempMin ;
     }

     public   double  getTempMax ()   {
         return  tempMax ;
     }

     public   void  setTempMax ( double  tempMax )   {
         this . tempMax  =  tempMax ;
     }

     public   int  getHumidity ()   {
         return  humidity ;
     }

     public   void  setHumidity ( int  humidity )   {
         this . humidity  =  humidity ;
     }

     public   double  getWindSpeed ()   {
         return  windSpeed ;
     }

     public   void  setWindSpeed ( double  windSpeed )   {
         this . windSpeed  =  windSpeed ;
     }

     public   String  getCity ()   {
         return  city ;
     }

     public   void  setCity ( String  city )   {
         this . city  =  city ;
     }

     public   String  getIcon ()   {
         return  icon ;
     }

     public   void  setIcon ( String  icon )   {
         this . icon  =  icon ;
     }

     public   int  getConditionCode ()   {
         return  conditionCode ;
     }

     public   void  setConditionCode ( int  conditionCode )   {
         this . conditionCode  =  conditionCode ;
     }
}

weather_app/src/main/java/com/service/weather/model/ZipCode.java

weather_app/src/main/java/com/service/weather/model/ZipCode.java

package  com . service . weather . model ;

import  jakarta . persistence . Entity ;
import  jakarta . persistence . GeneratedValue ;
import  jakarta . persistence . GenerationType ;
import  jakarta . persistence . Id ;

/**
 * The ZipCode class represents a record of Zipcode data.
 */
@ Entity
public   class   ZipCode   {

    @ Id
    @ GeneratedValue ( strategy  =   GenerationType . AUTO )
     private   Long  id ;
     private   String  city ;
     private   String  zipCode ;

     public   ZipCode ()   {
     }

     public   ZipCode ( Long  id ,   String  city ,   String  zipCode )   {
         this . id  =  id ;
         this . city  =  city ;
         this . zipCode  =  zipCode ;
     }

     public   Long  getId ()   {
         return  id ;
     }

     public   void  setId ( Long  id )   {
         this . id  =  id ;
     }

     public   String  getCity ()   {
         return  city ;
     }

     public   void  setCity ( String  city )   {
         this . city  =  city ;
     }

     public   String  getZipCode ()   {
         return  zipCode ;
     }

     public   void  setZipCode ( String  zipCode )   {
         this . zipCode  =  zipCode ;
     }
}

weather_app/src/main/java/com/service/weather/repository/ZipCodeRepository.java

weather_app/src/main/java/com/service/weather/repository/ZipCodeRepository.java

package  com . service . weather . repository ;

import  com . service . weather . model . ZipCode ;
import  org . springframework . data . jpa . repository . JpaRepository ;
import  org . springframework . stereotype . Repository ;

@ Repository
public   interface   ZipCodeRepository   extends   JpaRepository < ZipCode ,   Long >   {
}

weather_app/src/main/java/com/service/weather/service/DataInitializer.java

weather_app/src/main/java/com/service/weather/service/DataInitializer.java

package  com . service . weather . service ;

import  com . service . weather . model . ZipCode ;
import  com . service . weather . repository . ZipCodeRepository ;
import  jakarta . annotation . PostConstruct ;
import  org . springframework . beans . factory . annotation . Autowired ;
import  org . springframework . stereotype . Service ;

/**
 * The DataInitializer class is responsible for initializing the database with some default zip codes.
 * It checks if the database is empty and, if so, adds a predefined set of zip codes.
 */
@ Service
public   class   DataInitializer   {

    @ Autowired
     private   ZipCodeRepository  zipCodeRepository ;

    @ PostConstruct
     public   void  init ()   {
         // Check if zip codes are already in the database
         if   ( zipCodeRepository . count ()   ==   0 )   {
             // Add initial zip codes
            zipCodeRepository . save ( new   ZipCode ( null ,   "New York" ,   "10001" ));
            zipCodeRepository . save ( new   ZipCode ( null ,   "San Francisco" ,   "94114" ));
            zipCodeRepository . save ( new   ZipCode ( null ,   "Plano" ,   "75075" ));
         }
     }
}

weather_app/src/main/java/com/service/weather/service/WeatherService.java

weather_app/src/main/java/com/service/weather/service/WeatherService.java

package  com . service . weather . service ;

import  com . service . weather . model . OpenWeatherMapResponse ;
import  com . service . weather . model . WeatherRecord ;
import  org . springframework . beans . factory . annotation . Autowired ;
import  org . springframework . beans . factory . annotation . Value ;
import  org . springframework . stereotype . Service ;
import  org . springframework . web . client . RestTemplate ;

/**
 * The WeatherService class is responsible for fetching and processing weather data from the OpenWeatherMap API.
 * It retrieves weather information based on a provided zip code and converts the response into a WeatherRecord object.
 */
@ Service
public   class   WeatherService   {

    @ Autowired
     private   RestTemplate  restTemplate ;

    @ Value ( "${openweathermap.api.key}" )
     private   String  apiKey ;

     private   final   String  BASE_URL  =   "http://api.openweathermap.org/data/2.5/weather" ;
     private   final   String  ICON_URL  =   "https://openweathermap.org/img/wn/" ;

     /**
     * Fetches weather data for a given zip code from the OpenWeatherMap API.
     *
     *  @param  zipCode the zip code for which to fetch the weather
     *  @return  a WeatherRecord object containing the fetched weather data
     */
     public   WeatherRecord  getWeatherByZipCode ( String  zipCode )   {
         String  url  =   String . format ( "%s?zip=%s,us&units=imperial&appid=%s" ,  BASE_URL ,  zipCode ,  apiKey );
         OpenWeatherMapResponse  response  =  restTemplate . getForObject ( url ,   OpenWeatherMapResponse . class );

         if   ( response  !=   null )   {
             WeatherRecord  record  =   new   WeatherRecord ();
            record . setZipCode ( zipCode );
            record . setTemperature ( response . getMain (). getTemp ());
            record . setFeelsLike ( response . getMain (). getFeels_like ());
            record . setTempMin ( response . getMain (). getTemp_min ());
            record . setTempMax ( response . getMain (). getTemp_max ());
            record . setHumidity ( response . getMain (). getHumidity ());
            record . setWindSpeed ( response . getWind (). getSpeed ());
            record . setCity ( response . getName ());
             String  iconCode  =  response . getWeather (). get ( 0 ). getIcon ();
             String  iconUrl  =   String . format ( "%s%[email protected]" ,  ICON_URL ,  iconCode );
            record . setIcon ( iconUrl );
            record . setConditionCode ( response . getWeather (). get ( 0 ). getId ());
             return  record ;
         }   else   {
             throw   new   RuntimeException ( "Unable to fetch weather data" );
         }
     }
}

weather_app/src/main/java/com/service/weather/service/ZipCodeService.java

weather_app/src/main/java/com/service/weather/service/ZipCodeService.java

package  com . service . weather . service ;

import  com . service . weather . model . ZipCode ;
import  com . service . weather . repository . ZipCodeRepository ;
import  org . springframework . beans . factory . annotation . Autowired ;
import  org . springframework . stereotype . Service ;

import  java . util . List ;

/**
 * The ZipCodeService class provides business logic for handling zip code operations.
 * It interacts with the ZipCodeRepository to perform CRUD operations on zip code data.
 */
@ Service
public   class   ZipCodeService   {

    @ Autowired
     private   ZipCodeRepository  zipCodeRepository ;

     public   List < ZipCode >  getAllZipCodes ()   {
         return  zipCodeRepository . findAll ();
     }

     public   ZipCode  addZipCode ( ZipCode  zipCode )   {
         return  zipCodeRepository . save ( zipCode );
     }

     public   void  removeZipCode ( Long  id )   {
        zipCodeRepository . deleteById ( id );
     }
}

weather_app/src/main/java/com/service/weather/WeatherApplication.java

weather_app/src/main/java/com/service/weather/WeatherApplication.java

package  com . service . weather ;

import  org . springframework . boot . SpringApplication ;
import  org . springframework . boot . autoconfigure . SpringBootApplication ;
import  org . springframework . context . annotation . Bean ;
import  org . springframework . context . annotation . ComponentScan ;
import  org . springframework . web . client . RestTemplate ;

@ SpringBootApplication
@ ComponentScan ( basePackages  =   "com.service.weather" )
public   class   WeatherApplication   {

     public   static   void  main ( String []  args )   {
         SpringApplication . run ( WeatherApplication . class ,  args );
     }

    @ Bean
     public   RestTemplate  restTemplate ()   {
         return   new   RestTemplate ();
     }

}

weather_app/src/main/resources/application.properties

server..port=8090 spring.application.name=weather # H2 Database Configuration spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # JPA Configuration spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true openweathermap.api.key=5f40dfe3704a02e2e7a64d58dcefc566

weather_app/src/main/resources/static/css/styles.css

body { font-family: 'Arial', sans-serif; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; background: linear-gradient(to right, #6a11cb, #2575fc); color: #fff; height: 100vh; justify-content: space-between; } .container { width: 90%; max-width: 600px; padding: 20px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } header { text-align: center; margin-bottom: 20px; } h1 { font-size: 2.5em; margin: 0; color: #fff; } h2 { margin-bottom: 10px; } form { display: flex; justify-content: center; margin-bottom: 20px; } input { padding: 10px; font-size: 16px; border: none; border-radius: 5px; margin-right: 10px; } button { padding: 10px 20px; font-size: 16px; cursor: pointer; border: none; border-radius: 5px; background-color: #2575fc; color: #fff; transition: background-color 0.3s ease; } button:hover { background-color: #6a11cb; } #weatherResult, #savedWeatherResults { font-size: 18px; color: #fff; } #zipCodeList { list-style: none; padding: 0; width: 100%; } #zipCodeList li { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; background: rgba(255, 255, 255, 0.2); padding: 10px; border-radius: 5px; } #zipCodeList li span { flex: 1; } .weather-container { display: flex; border: 2px solid #ccc; border-radius: 10px; padding: 20px; max-width: 800px; margin: 20px auto; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); background: rgba(255, 255, 255, 0.1); } .weather-header, .weather-details { flex: 1; margin: 10px; } .weather-header { display: flex; flex-direction: column; align-items: center; justify-content: center; border-right: 2px solid #ccc; padding-right: 20px; } .city-name { font-size: 1.5em; font-weight: bold; } .weather-icon { width: 50px; height: 50px; } .temperature { font-size: 2em; color: #f39c12; } .weather-details { background-color: #f2f2f2; padding: 10px; border-radius: 10px; display: flex; flex-direction: column; justify-content: center; color: #000; } .weather-details p { margin: 5px 0; } #zipCodeList li button { margin-left: 10px; padding: 5px 10px; border: none; border-radius: 5px; background-color: #ff4e50; color: #fff; cursor: pointer; transition: background-color 0.3s ease; } #zipCodeList li button:hover { background-color: #fc913a; } .scroll-container { display: flex; overflow-x: auto; padding: 10px 0; } #popularZipCodeList { display: flex; flex-direction: row; list-style: none; padding: 0; margin: 0; } #popularZipCodeList li { display: flex; flex-direction: column; align-items: center; justify-content: center; margin-right: 10px; background: rgba(255, 255, 255, 0.2); padding: 10px; border-radius: 5px; color: #fff; min-width: 100px; border: 1px solid #fff; } #popularZipCodeList li span { margin-bottom: 5px; } #popularZipCodeList li button { margin-top: 5px; padding: 5px 10px; border: none; border-radius: 5px; background-color: #ff4e50; color: #fff; cursor: pointer; transition: background-color 0.3s ease; } #popularZipCodeList li button:hover { background-color: #fc913a; }

weather_app/src/main/resources/static/index.html

Weather App

Search Weather by Zip Code

Get Weather

Add Zip Code to List

Add to List

Saved Zip Codes

    Popular Weather Locations

      © 2024 Weather App. All rights reserved.

weather_app/src/main/resources/static/js/script.js

document.addEventListener('DOMContentLoaded', function() { const weatherForm = document.getElementById('weatherForm'); const addZipForm = document.getElementById('addZipForm'); const zipCodeInput = document.getElementById('zipCode'); const addZipCodeInput = document.getElementById('addZipCode'); const weatherResult = document.getElementById('weatherResult'); const zipCodeList = document.getElementById('zipCodeList'); const savedWeatherResults = document.getElementById('savedWeatherResults'); const popularZipCodeList = document.getElementById('popularZipCodeList'); // Load stored zip codes and display weather for each loadStoredZipCodes(); // Load popular zip codes from the database loadZipCodesFromDB(); // Add event listener to the weather form for fetching weather data weatherForm.addEventListener('submit', function(event) { event.preventDefault(); const zipCode = zipCodeInput.value; fetchWeather(zipCode, weatherResult); }); // Add event listener to the add zip code form for adding a new zip code to the list addZipForm.addEventListener('submit', function(event) { event.preventDefault(); const zipCode = addZipCode.value; addZipCodeToList(zipCode); }); // Function to fetch weather data for a given zip code and display it function fetchWeather(zipCode, resultElement) { fetch(`/api/weather?zipCode=${zipCode}`) .then(response => { if (response.status === 500) { throw new Error('Invalid zip code'); } return response.json(); }) .then(data => { // Check for severe weather conditions if (isSevereWeather(data.conditionCode)) { alert(`Severe weather condition detected in ${data.city} (ZIP: ${zipCode}): ${getDescriptionForConditionCode(data.conditionCode)}`); } const weatherIcon = data.icon; const weatherInfo = ` <div id="weatherResult" class="weather-container"> <div class="weather-header"> <div class="city-name">${data.city}</div> <img src="${weatherIcon}" alt="Weather Icon" class="weather-icon" onerror="this.onerror=null; this.src='/images/default.png';"> <div class="temperature">${data.temperature} °F</div> </div> <div class="weather-details"> <p>Feels Like: ${data.feelsLike} °F</p> <p>Min Temp: ${data.tempMin} °F</p> <p>Max Temp: ${data.tempMax} °F</p> <p>Humidity: ${data.humidity} %</p> <p>Wind Speed: ${data.windSpeed} mph</p> </div> </div> `; resultElement.innerHTML = weatherInfo; }) .catch(error => { console.error('Error fetching weather data:', error); if (error.message === 'Invalid zip code') { alert('The provided zip code does not exist. Please enter a valid zip code.'); resultElement.innerHTML = 'Error: Invalid zip code'; } else { resultElement.innerHTML = 'Error fetching weather data'; } }); } // Function to check if the weather condition is severe based on the condition code function isSevereWeather(conditionCode) { const severeConditions = [200, 201, 202, 210, 211, 212, 221, 230, 231, 232, 502, 503, 504, 511, 522, 531, 601, 602, 622, 711, 731, 741, 751, 761, 762, 771, 781]; return severeConditions.includes(conditionCode); } // Function to get the description for a specific weather condition code function getDescriptionForConditionCode(conditionCode) { const conditionDescriptions = { 200: 'thunderstorm with light rain', 201: 'thunderstorm with rain', 202: 'thunderstorm with heavy rain', 210: 'light thunderstorm', 211: 'thunderstorm', 212: 'heavy thunderstorm', 221: 'ragged thunderstorm', 230: 'thunderstorm with light drizzle', 231: 'thunderstorm with drizzle', 232: 'thunderstorm with heavy drizzle', 502: 'heavy intensity rain', 503: 'very heavy rain', 504: 'extreme rain', 511: 'freezing rain', 522: 'heavy intensity shower rain', 531: 'ragged shower rain', 601: 'snow', 602: 'heavy snow', 622: 'heavy shower snow', 711: 'smoke', 731: 'sand/dust whirls', 741: 'fog', 751: 'sand', 761: 'dust', 762: 'volcanic ash', 771: 'squalls', 781: 'tornado' }; return conditionDescriptions[conditionCode] || 'Unknown severe condition'; } // Function to add a new zip code to the list and fetch its weather data function addZipCodeToList(zipCode) { const tempResultElement = document.createElement('div'); fetch(`/api/weather?zipCode=${zipCode}`) .then(response => { if (response.status === 500) { throw new Error('Invalid zip code'); } return response.json(); }) .then(data => { let storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; if (!storedZipCodes.includes(zipCode)) { storedZipCodes.push(zipCode); localStorage.setItem('zipCodes', JSON.stringify(storedZipCodes)); displayStoredZipCodes(storedZipCodes); fetchWeatherForSavedZipCode(zipCode); } }) .catch(error => { console.error('Error fetching weather data:', error); if (error.message === 'Invalid zip code') { alert('The provided zip code does not exist. Please enter a valid zip code.'); } }); } // Function to load stored zip codes from localStorage and display their weather data function loadStoredZipCodes() { const storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; displayStoredZipCodes(storedZipCodes); storedZipCodes.forEach(zipCode => fetchWeatherForSavedZipCode(zipCode)); } // Function to load popular zip codes from the database and display their weather data function loadZipCodesFromDB() { fetch('/api/zipcodes') .then(response => response.json()) .then(data => { const zipCodes = data.map(item => item.zipCode); displayPopularZipCodes(zipCodes); zipCodes.forEach(zipCode => fetchWeatherForPopularZipCode(zipCode)); }) .catch(error => console.error('Error fetching zip codes from DB:', error)); } // Function to display stored zip codes in the UI function displayStoredZipCodes(zipCodes) { zipCodeList.innerHTML = ''; zipCodes.forEach(zipCode => { const listItem = document.createElement('li'); const zipCodeText = document.createElement('span'); zipCodeText.textContent = zipCode; const resultElement = document.createElement('div'); resultElement.id = `weatherResult-${zipCode}`; resultElement.classList.add('weather-info'); const deleteButton = document.createElement('button'); deleteButton.textContent = 'Delete from list'; deleteButton.addEventListener('click', () => removeZipCode(zipCode)); listItem.appendChild(zipCodeText); listItem.appendChild(resultElement); listItem.appendChild(deleteButton); zipCodeList.appendChild(listItem); }); } // Function to display popular zip codes in the UI function displayPopularZipCodes(zipCodes) { popularZipCodeList.innerHTML = ''; zipCodes.forEach(zipCode => { const listItem = document.createElement('li'); const zipCodeText = document.createElement('span'); zipCodeText.textContent = zipCode; const resultElement = document.createElement('div'); resultElement.id = `popularWeatherResult-${zipCode}`; resultElement.classList.add('weather-info'); listItem.appendChild(zipCodeText); listItem.appendChild(resultElement); popularZipCodeList.appendChild(listItem); }); } // Function to fetch weather data for a popular zip code and display it function fetchWeatherForPopularZipCode(zipCode) { const resultElement = document.getElementById(`popularWeatherResult-${zipCode}`); if (resultElement) { fetchWeather(zipCode, resultElement); } } // Function to fetch weather data for a saved zip code and display it function fetchWeatherForSavedZipCode(zipCode) { const resultElement = document.getElementById(`weatherResult-${zipCode}`); if (resultElement) { fetchWeather(zipCode, resultElement); } } // Function to remove a zip code from the list function removeZipCode(zipCode) { let storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; storedZipCodes = storedZipCodes.filter(storedZipCode => storedZipCode !== zipCode); localStorage.setItem('zipCodes', JSON.stringify(storedZipCodes)); displayStoredZipCodes(storedZipCodes); } });

weather_app/src/test/java/com/service/weather/DataInitializerTest.java

weather_app/src/test/java/com/service/weather/DataInitializerTest.java

package  com . service . weather ;

import  com . service . weather . model . ZipCode ;
import  com . service . weather . repository . ZipCodeRepository ;
import  com . service . weather . service . DataInitializer ;
import  org . junit . jupiter . api . BeforeEach ;
import  org . junit . jupiter . api . Test ;
import  org . junit . jupiter . api . extension . ExtendWith ;
import  org . mockito . InjectMocks ;
import  org . mockito . Mock ;
import  org . mockito . junit . jupiter . MockitoExtension ;

import   static  org . mockito . Mockito . * ;

/**
 * The DataInitializerTest class tests the DataInitializer class to ensure that it initializes the database correctly.
 * It uses Mockito to mock the ZipCodeRepository and verifies interactions with it.
 */
@ ExtendWith ( MockitoExtension . class )
public   class   DataInitializerTest   {

    @ Mock
     private   ZipCodeRepository  zipCodeRepository ;

    @ InjectMocks
     private   DataInitializer  dataInitializer ;

    @ BeforeEach
     public   void  setUp ()   {
         // Ensure the mock repository is empty before each test
        when ( zipCodeRepository . count ()). thenReturn ( 0L );
     }

    @ Test
     public   void  testInit ()   {
        when ( zipCodeRepository . count ()). thenReturn ( 0L );

        dataInitializer . init ();

        verify ( zipCodeRepository ,  times ( 1 )). count ();

        verify ( zipCodeRepository ,  times ( 1 )). save ( argThat ( zipCode  ->
                zipCode . getCity (). equals ( "New York" )   &&  zipCode . getZipCode (). equals ( "10001" )
         ));

        verify ( zipCodeRepository ,  times ( 1 )). save ( argThat ( zipCode  ->
                zipCode . getCity (). equals ( "San Francisco" )   &&  zipCode . getZipCode (). equals ( "94114" )
         ));

        verify ( zipCodeRepository ,  times ( 1 )). save ( argThat ( zipCode  ->
                zipCode . getCity (). equals ( "Plano" )   &&  zipCode . getZipCode (). equals ( "75075" )
         ));
     }

    @ Test
     public   void  testInitWithExistingData ()   {
         // Simulate existing data in the repository
        when ( zipCodeRepository . count ()). thenReturn ( 3L );

        dataInitializer . init ();

        verify ( zipCodeRepository ,  never ()). save ( any ( ZipCode . class ));
     }
}

weather_app/src/test/java/com/service/weather/WeatherApplicationTests.java

weather_app/src/test/java/com/service/weather/WeatherApplicationTests.java

package  com . service . weather ;

import  com . service . weather . model . OpenWeatherMapResponse ;
import  com . service . weather . model . WeatherRecord ;
import  com . service . weather . service . WeatherService ;
import  org . junit . jupiter . api . BeforeEach ;
import  org . junit . jupiter . api . Test ;
import  org . junit . jupiter . api . extension . ExtendWith ;
import  org . mockito . InjectMocks ;
import  org . mockito . Mock ;
import  org . mockito . junit . jupiter . MockitoExtension ;
import  org . springframework . beans . factory . annotation . Value ;
import  org . springframework . web . client . RestTemplate ;

import  java . util . Arrays ;

import   static  org . junit . jupiter . api . Assertions . assertEquals ;
import   static  org . junit . jupiter . api . Assertions . assertNotNull ;
import   static  org . mockito . ArgumentMatchers . any ;
import   static  org . mockito . ArgumentMatchers . anyString ;
import   static  org . mockito . Mockito . when ;

@ ExtendWith ( MockitoExtension . class )
class   WeatherApplicationTests   {

    @ Mock
     private   RestTemplate  restTemplate ;

    @ InjectMocks
     private   WeatherService  weatherService ;

    @ Value ( "${openweathermap.api.key}" )
     private   String  apiKey ;

     private   final   String  zipCode  =   "90210" ;
     private   OpenWeatherMapResponse  mockResponse ;

    @ BeforeEach
     public   void  setUp ()   {
        mockResponse  =   new   OpenWeatherMapResponse ();
         OpenWeatherMapResponse . Main  main  =   new   OpenWeatherMapResponse . Main ();
        main . setTemp ( 72.0 );
        main . setFeels_like ( 70.0 );
        main . setTemp_min ( 68.0 );
        main . setTemp_max ( 75.0 );
        main . setHumidity ( 50 );
         OpenWeatherMapResponse . Wind  wind  =   new   OpenWeatherMapResponse . Wind ();
        wind . setSpeed ( 5.0 );
         OpenWeatherMapResponse . Weather  weather  =   new   OpenWeatherMapResponse . Weather ();
        weather . setIcon ( "10d" );
        weather . setId ( 800 );
        mockResponse . setMain ( main );
        mockResponse . setWind ( wind );
        mockResponse . setWeather ( Arrays . asList ( weather ));
        mockResponse . setName ( "New York" );

        when ( restTemplate . getForObject ( anyString (),  any ())). thenReturn ( mockResponse );
     }

    @ Test
     public   void  testGetWeatherByZipCode ()   {
         WeatherRecord  result  =  weatherService . getWeatherByZipCode ( zipCode );

        assertNotNull ( result );
        assertEquals ( zipCode ,  result . getZipCode ());
        assertEquals ( 72.0 ,  result . getTemperature ());
        assertEquals ( 70.0 ,  result . getFeelsLike ());
        assertEquals ( 68.0 ,  result . getTempMin ());
        assertEquals ( 75.0 ,  result . getTempMax ());
        assertEquals ( 50 ,  result . getHumidity ());
        assertEquals ( 5.0 ,  result . getWindSpeed ());
        assertEquals ( "New York" ,  result . getCity ());
        assertEquals ( "https://openweathermap.org/img/wn/[email protected]" ,  result . getIcon ());
        assertEquals ( 800 ,  result . getConditionCode ());
     }

    @ Test
     public   void  testGetWeatherByZipCodeWithEmptyResponse ()   {
        when ( restTemplate . getForObject ( anyString (),  any ())). thenReturn ( null );

         RuntimeException  exception  =   null ;
         try   {
            weatherService . getWeatherByZipCode ( zipCode );
         }   catch   ( RuntimeException  e )   {
            exception  =  e ;
         }

        assertNotNull ( exception );
        assertEquals ( "Unable to fetch weather data" ,  exception . getMessage ());
     }
}

weather_app/src/test/java/com/service/weather/ZipCodeServiceTest.java

weather_app/src/test/java/com/service/weather/ZipCodeServiceTest.java

package  com . service . weather ;

import  com . service . weather . model . ZipCode ;
import  com . service . weather . repository . ZipCodeRepository ;
import  com . service . weather . service . ZipCodeService ;
import  org . junit . jupiter . api . BeforeEach ;
import  org . junit . jupiter . api . Test ;
import  org . junit . jupiter . api . extension . ExtendWith ;
import  org . mockito . InjectMocks ;
import  org . mockito . Mock ;
import  org . mockito . junit . jupiter . MockitoExtension ;

import  java . util . Arrays ;
import  java . util . List ;

import   static  org . junit . jupiter . api . Assertions . * ;
import   static  org . mockito . Mockito . * ;

@ ExtendWith ( MockitoExtension . class )
public   class   ZipCodeServiceTest   {

    @ Mock
     private   ZipCodeRepository  zipCodeRepository ;

    @ InjectMocks
     private   ZipCodeService  zipCodeService ;

     private   ZipCode  zipCode1 ;
     private   ZipCode  zipCode2 ;

    @ BeforeEach
     public   void  setUp ()   {
        zipCode1  =   new   ZipCode ( 1L ,   "City1" ,   "10001" );
        zipCode2  =   new   ZipCode ( 2L ,   "City2" ,   "10002" );
     }

    @ Test
     public   void  testGetAllZipCodes ()   {
        when ( zipCodeRepository . findAll ()). thenReturn ( Arrays . asList ( zipCode1 ,  zipCode2 ));
         List < ZipCode >  zipCodes  =  zipCodeService . getAllZipCodes ();
        assertEquals ( 2 ,  zipCodes . size ());
        verify ( zipCodeRepository ,  times ( 1 )). findAll ();
     }

    @ Test
     public   void  testAddZipCode ()   {
        when ( zipCodeRepository . save ( zipCode1 )). thenReturn ( zipCode1 );
         ZipCode  savedZipCode  =  zipCodeService . addZipCode ( zipCode1 );
        assertNotNull ( savedZipCode );
        assertEquals ( "10001" ,  savedZipCode . getZipCode ());
        verify ( zipCodeRepository ,  times ( 1 )). save ( zipCode1 );
     }

    @ Test
     public   void  testRemoveZipCode ()   {
        doNothing (). when ( zipCodeRepository ). deleteById ( 1L );
        zipCodeService . removeZipCode ( 1L );
        verify ( zipCodeRepository ,  times ( 1 )). deleteById ( 1L );
     }
}

weather_app/weather.iml

,

CMSC 495 FINAL REPORT 1

Final Report

Names of Group Members

CMSC 495 – Section XXXX

DATE

CMSC 495 FINAL REPORT 2

Table of Contents

1. Overview …………………………………………………………………………………………………………… 3

2. Project Plan ……………………………………………………………………………………………………….. 4

3. Requirements Specification ………………………………………………………………………………….. 4

4. System Specification ……………………………………………………………………………………………. 4

5. User's Guide ………………………………………………………………………………………………………. 4

6. Test Plan and Results ………………………………………………………………………………………….. 5

7. Design and Alternate designs ………………………………………………………………………………… 5

8. Development History …………………………………………………………………………………………… 8

9. Conclusions ……………………………………………………………………………………………………… 11

9.1. Lessons Learned ……………………………………………………………………………………………………. 11

9.2 Design Strengths ……………………………………………………………………………………………………. 12

9.3 Limitations ……………………………………………………………………………………………………………. 13

9.4. Suggestions for Future Improvement ……………………………………………………………………….. 13

CMSC 495 FINAL REPORT 3

1. Overview

The Plate License and Tag Editor (PLaTE) application was designed to automate the license

plate management division of the DMV. Features provided by the application include:

 License plate data management including adding and deleting records

 Renewals of existing license plates

 Ordering new license plates

 Sending payment information to credit card companies securely

 Storage of application data including customer data, vehicle data, license plate data

The application operates though a Python based Graphic User Interface (GUI) with a SQL based

database for information storage. The application runs on either Windows or Mac systems that

have python and SQLite loaded on the system.

The application has 3 major components, the GUI, the database, and the backend code.

Development of the system was accomplished by a two-person team (Pearce, Rosario-Baez).

Being that the development team had a limited manpower pool, the entire development team

were involved almost every of the application management and oversight of the major portions

of the development were assigned to specific individuals as follows:

 GUI development – Name 1

 Database management – Name 2

 Python application backend code – Name 3

 Documentation – Name

CMSC 495 FINAL REPORT 4

2. Project Plan

The finalized Version 3 of the Project Plan is embedded in this document. Open it by clicking on

the icon below.

3. Requirements Specification

Requirement specifications are covered in the finalized project plan. Access it by clicking on the

icon in the previous section.

4. System Specification

The application will come with the Python GUI, SQL code to place the required tables on any

SQL database, and the Python code to run the GUI/SQL database integration. The Python GUI

will communicate with the SQL database to add, view, and delete customer records. These

records will be used to keep track who owns a vehicle in the state of Maryland and help

Maryland drivers renew and obtain new license plates to maintain proper ownership of the

vehicle.

5. User's Guide

The PLaTE Version 3 User Guide is a comprehensive document that has been vetted by the team

and the professor on through multiple revisions. The current revision is a clearly laid out step-by-

step guide to every function of the PLaTE program. Each process contains figures of each step of

5 CMSC 495 FINAL REPORT

the process to guide an inexperienced user through the program. The finalized Version 3 of

the User Guide is embedded in this document. Open it by clicking on the icon below.

6. Test Plan and Results

The test plan documents, and results have been key to ensuring that the release of our program

was successful. Combing the GUI and associated code step by step with the test pans have

helped us to identify problems that would have made it into production. All problems found have

been fixed until the test plan could be ran with no failures

The Finalized Test Plan and its attachments are embedded in this document. Open them by

clicking on their icons below.

7. Design and Alternate designs

Primary designs for the program were comprehensive, the original program UML is shown

below:

CMSC 495 FINAL REPORT 6

UML

Figure 1. UML Part 1

Figure 2. UML Part 2

CMSC 495 FINAL REPORT 7

Although this fix helped the user to be able to easily see records, we quickly realized that we did

not take into consideration that a customer could own more than one car and could there for have

multiple cars and plates that would have to be connected and able to be accessed individually for

display and renewal. purposes. The solution to that was several functions and a new window.

The new functionality of the program made the program look to see if a customer had more than

one vehicle when their driver’s license was entered in the normal process. If there was only one

record everything processed as normal. If there was more than one the window below would

open showing the VIN, make, model, and year for all the vehicles associated with the driver’s

license entered.

Figure 3. UML Part 3

CMSC 495 FINAL REPORT 8

Figure 4. Multiple Record User Interface

The user could then choose which record they wished to use by clicking on the record in the

displayed list and pressing submit. The record that was selected would then process. This

window and the functionality attached it fixed a major shortfall in the program. The program

remains in its final state with only the addition of this one window and popups to tell users the

success or failures of their entries.

The Finalized Design Plan is embedded in this document. Open it by clicking on their icons

below.

8. Development History

The Plate program s developmental history is best displayed through our milestone chart and

later quite comprehensively through our phase submissions. On the milestone chart shown

below, the black lines show the milestones as they were set at the beginning of the project. The

CMSC 495 FINAL REPORT 9

green lines show the actual times. Most time frames were very close to the prospective times set

forth at the beginning. Times for GUI assembly, backend coding, and connection of components

are shown longer as the GUI and its functionality was an ongoing process after the initial build

for the entire project. All of these times ran over their estimates but concluded in plenty of time

while leaving a much better program than in the beginning.

Figure 5. Milestones of the Project VS Actual Times

10 CMSC 495 FINAL REPORT

An overview of the three phases of this developmental processes where as follows:

PHASE I (5 Sept 15 – Sept 21)

Name Got to work on learning PYSimpleGUI and getting the initial build of the GUI together.

This was a major undertaking as neither member of the team had ever used Python to write a

GUI.

Name started writing pseudo functions for the backend and creating SQL tables that would hold

the data needed for the program and hold enough information on each customer, vehicle, and

license plate so that they could be attached to their corresponding records and be used by the

GUI and backend code.

PHASE II (Sept 22 – Sept 28)

Namecontinue to work on the GUI, adding functionality while coordinating with Pearce to

ensure that the backend code was written to correspond with the database as it was coming

together.

Name added 20 rows of values to each table to use when constructing the backend code. Pearce

then wrote code into each function, testing that each function worked with the SQL database

adding, deleting, and viewing the information from the database.

PHASE III (Sept 29 – Oct 5)

The program is functionally complete at this point and bugs are being discovered as we wade

through testing. At this point in the project both member of the team had to be very careful of

version control. Coding was often done on Zoom with both member working through any

problems that had arisen.

CMSC 495 FINAL REPORT 11

9. Conclusions

Over the past eight weeks, team one has put their shoulder to the wheel and fought through some

difficult learning curves. Despite all that, we feel that the product we produced is hearty and does

what we want it to. We did not, at any time during the process, say to ourselves, “let’s skip this

functionality so that we can get this thing done”. We fought through some areas, but all aspects

of the program’s functionality were as we envisioned them and some even turned out better than

we had expected. Both team members are much better programmers and project coordinators

because of the programming tasks and teamwork involved in this project.

9.1. Lessons Learned

There are several lessons learned during this project:

First, be flexible. There will almost always be design changes that must happen once you start

coding. They may be small, but they may affect other parts of the program. Accept that this is

going to happen and don’t try to stall or hide them. Triage them as they are found and decide

what needs to be done to make things right. We ran into a few such items in our code as we went

along. Either a program logic item that we had not considered or one that we had considered but

when applied acted differently. We discussed fixes when the problems were identified and got

after it. We are proud to say that there is not one problem, that we identified that, that we did not

fix.

Next, keep to your timelines if possible. We set milestones and either kept or exceeded

them. This allowed us time to meet incoming problems head on. Not only in our code but in our

home life and jobs. Because we stayed a focused and did not let ourselves get behind on the

CMSC 495 FINAL REPORT 12

coding or the documentation, we were able to overcome not only unseen code problems but also

events that were out of the team’s control that took a team member offline for a day or two.

Lastly, the answers are out there. We are fortunate today to have a vast repository of

knowledge at our fingertips. If you wish to learn or clarify something. The answer is most often

just a internet search away. We were lacking some of the knowledge we needed to complete this

project at the beginning. We identified that fact early and taught ourselves what we needed with

many hours of research. The lesson learned is that you can do almost anything with coding

today, it may take some research, but it is possible.

9.2 Design Strengths

Our program is solidly built and held together with strong code. Lines of code that were used

more than once were made into functions so that they could be managed easier, and the code

would be easier to read from an outside perspective. We did not allow for covering or burying

flaws that we found while testing. If a rewrite of a section of the code was required to fix issues

raised by testing, it was rewritten. This would often set us back, but we had made provisions in

the planning for this and stayed with or ahead of our timeline as a rule.

We designed the program to be easy to use. Sections of the GUI that require use input are

highlighted when that input is needed. All other input areas are shaded out. Popup boxes notify

users when they are using the program incorrectly or when errors are made during data input.

Visual examples are given of plates as they are ordered aid the user and customer to verify what

they are ordering.

CMSC 495 FINAL REPORT 13

The GUI is easily modifiable. Future upgrades to the program could easily modify, replace, or

add windows in response to user feedback. This will allow the software development cycle to

continue easily as it comes around in its cyclical manner.

9.3 Limitations

As far as limitations go for the program, our team focused on removing limitations when they

were discovered in the design process or when coding started. That is not to say that our program

does not have limitations. It means that we have far fewer limitation than we would have if we

would not have worked under that credo. There are limitations both remaining both

programmatically and structurally.

 The SQLite database will only hold approximately 281 terabytes of data. (SQLite.org,

2021)

 Each table in the database can only hold 18,446,744,073,709,551,616 rows of data

(SQLite.org, 2021)

 We currently do not automatically track expiration dates in the database. This must be

done manually and could be made automated in future releases of the program

 Current versions of Python and SQLite must be loaded on each machine that wishes to

use the program.

9.4. Suggestions for Future Improvement

Our team has kept an eye out for future improvements as the program was coming together.

Some of those improvements that were identified we were able to incorporate immediately.

Others were noted for the future. One of the upgrades we were able to incorporate was the ability

CMSC 495 FINAL REPORT 14

to select which record was being selected when the customer hand more than one vehicle. How

the user performed this task was upgraded from a manual count of the records by the user to a

list populated with the options available that the user can click on their selection and submit it.

There was a lot of blood sweat and tears to bring that upgrade into production, but we

accomplished it and it works beautifully.

Some of the future improvements that we identified for future versions of the program was the

addition of more plate backgrounds beyond the eight versions we currently offer, an expiration

date tracker that automatically combs the database and provides that information to the user. This

task currently must be done manually. Lastly, combing the program into an executable file would

make the initial download and startup of the program easier and could be accomplished by an

average user instead of a programmer.

CMSC 495 FINAL REPORT 15

REFERENCES

Geeks for Geeks.org. (2019, March 27). Python | Convert list of tuples to list of list.

GeeksforGeeks. https://www.geeksforgeeks.org/python-convert-list-of-tuples-to-list-of-list/

Programiz. (n.d.). Python list remove(). Programiz: Learn to Code for

Free. https://www.programiz.com/python-programming/methods/list/remove

PySimpleGUI. (2021). PySimpleGUI. https://pysimplegui.readthedocs.io/en/latest/

Python, R. (2020, June 17). PySimpleGUI: The simple way to create a GUI with Python – Real Python.

Python Tutorials – Real Python. https://realpython.com/pysimplegui-python/

Python Software Foundation. (2021). Sqlite3 — DB-API 2.0 interface for SQLite databases — Python

3.9.7 documentation. 3.9.7 Documentation. https://docs.python.org/3/library/sqlite3.html

SQLite.org. (2021, June 18). Implementation limits for SQLite. SQLite. https://www.sqlite.org/limits.html

Trinket.io. (2021). The basics of the pysimplegui program. https://pysimplegui.trinket.io/demo-

programs#/demo-programs/the-basic-pysimplegui-program

Tutorialspoint. (2021). SQLite – Python. Biggest Online Tutorials

Library. https://www.tutorialspoint.com/sqlite/sqlite_python.htm

Tutorialspoint. (2021). SDLC – Overview. The Biggest Online Tutorials Library – AppML, AI with Python,

Behave, Java16, Spacy. https://www.tutorialspoint.com/sdlc/sdlc_overview.htm

W3 Schools. (2021). SQL SELECT statement. W3Schools Online Web

Tutorials. https://www.w3schools.com/sql/sql_select.asp

,

Title: Project Test Plan

Team Members:

Date: July 16, 2024

Introduction

The software project involves developing a weather website that allows users to input a zip code and receive real-time weather information. This website fetches weather data from an external API and displays various weather parameters, including temperature, humidity, wind speed, and weather conditions such as thunderstorms and heavy rain. The scope of testing for this project encompasses all functionalities of the website to ensure that it performs correctly under various conditions and provides a seamless user experience. This includes ensuring the accuracy of data, compatibility across different browsers, and reliability of the entire system to ensure it meets user requirements and expectations.

Testing Objectives

The primary objectives of the testing effort are to ensure that the weather website operates correctly and efficiently, providing a high-quality user experience. The specific quality attributes to be assessed include functionality, usability, and reliability. The testing will focus on:

· Functionality: Ensuring the core features such as zip code input, weather data retrieval, and display operate correctly. This includes verifying that users can add and remove zip codes, preventing duplicate entries, and handling both valid and invalid zip codes appropriately.

· Usability: Confirming that the user interface is intuitive and easy to navigate, providing a seamless user experience across different devices and screen sizes.

· Reliability: Ensuring the application is dependable, with saved zip codes persisting across sessions and accurate weather information being consistently provided.

By assessing these attributes, the testing effort aims to ensure that the weather website delivers accurate, timely, and reliable weather information while providing a user-friendly experience to its users.

Test Strategy

The overall approach to testing will involve a combination of manual and automated testing methodologies to ensure comprehensive coverage and efficiency. The testing types to be performed include unit testing, integration testing, system testing, and usability testing. Each type of testing plays a critical role in validating different aspects of the weather website, ensuring it meets the highest standards of quality and user satisfaction.

Unit Testing

Unit testing will focus on verifying the functionality of individual components within the system. Each module, such as the zip code input handler, weather data fetcher, and user interface components, will be tested in isolation. This helps identify and fix issues at an early stage, ensuring that each part of the application works as intended.

Automated unit tests will be written to cover various scenarios, including edge cases, to ensure robustness:

1. API Key and Weather Fetching:

· The unit test will mock the behavior of external API calls to ensure that the getWeatherByZipCode method correctly constructs the API URL, handles responses, and populates the WeatherRecord object.

· Tests will cover scenarios such as valid zip code responses, invalid zip codes returning errors, and no response from the API.

2. Error Handling and Edge Cases:

· Tests will verify that the system gracefully handles errors, such as invalid zip codes or network issues, by displaying appropriate messages and maintaining application stability.

· Edge cases, such as empty inputs or malformed zip codes, will be thoroughly tested to ensure robust input validation and error handling.

Integration Testing

Integration testing will verify that different components of the weather website work together seamlessly. This involves testing the interactions between the frontend and backend, as well as between various backend services. The goal is to ensure that data flows correctly through the system and that integrated components interact as expected. Integration tests will include scenarios such as fetching weather data for a given zip code and updating the user interface with the retrieved information.

System Testing

System testing will assess the end-to-end functionality of the entire weather website. This comprehensive testing approach will cover all user interactions and system workflows, from entering a zip code to displaying weather information and managing saved zip codes. System testing will ensure that the application meets its functional requirements and provides a reliable user experience.

Test Scope

The test scope includes all functional and non-functional aspects of the weather website. Functional testing will cover core features such as zip code input handling, weather data retrieval from the API, and the display of weather information on the user interface. Non-functional testing will assess usability, reliability, and cross-browser compatibility. The boundaries of the testing effort exclude testing on deprecated browsers, and network conditions outside typical user scenarios. Additionally, backend integrations with external weather data providers will be tested under the assumption that their APIs are functional and reliable.

Test Cases

The test will focus on the following test cases to ensure comprehensive coverage of the system's functionality:

1. Valid Zip Code Fetch: Verify that entering a valid zip code fetches and displays the correct weather information.

2. Invalid Zip Code Error: Ensure that entering an invalid zip code results in an appropriate error message without crashing the application.

3. Adding Valid Zip Code to List: Confirm that valid zip codes can be added to a list for quick access.

4. Invalid Zip Code Addition Prevention: Verify that attempting to add an invalid zip code does not add it to the list.

5. Prevent Duplicate Zip Codes in List: Ensure that duplicate zip codes cannot be added to the list.

6. Remove Zip Code from List: Check that users can remove zip codes from their saved list.

7. Fetch Weather for Saved Zip Codes on Load: Ensure that the weather information for saved zip codes is fetched and displayed when the application is loaded.

8. Severe Weather Alert: Verify that the application can handle and display alerts for severe weather conditions when a relevant zip code is entered.

9. Persistent Zip Codes on Reopen: Ensure that saved zip codes are retained and reloaded when the application is reopened.

10. Cross-Browser Compatibility: Confirm that the website functions correctly across different browsers such as Chrome, Firefox, Safari, and Edge.

Testing Procedures

Testing procedures will involve specific steps for executing each test case, including setting up the test environment, preparing test data, and recording results. Test data preparation will involve creating a set of valid and invalid zip codes, as well as simulating various user interactions. The test environment configuration will ensure that the backend server, frontend client, and network conditions are consistent with typical user scenarios.

Testing Schedule

The testing schedule for the weather website outlines the timelines for each phase of the testing effort, ensuring that all testing activities are completed within the project timeline. The schedule includes deadlines for unit testing, integration testing, system testing, and usability testing, with specific milestones and deliverables. Each phase has been allocated sufficient time for test case development, test execution, defect resolution, and re-testing. The testing schedule is as follows:

July 10 – July 11: Unit Testing

· July 10:

· Develop unit test cases for the zip code input handler and weather data fetcher.

· Set up the testing environment and write automated unit tests using JUnit and Mockito.

· July 11:

· Execute unit tests.

· Identify and log any defects found during unit testing.

· Begin fixing identified defects.

July 12 – July 14: Integration Testing

· July 12:

· Develop integration test cases to verify interactions between the frontend and backend components.

· Set up the testing environment for integration tests.

· July 13:

· Execute integration tests.

· Identify and log any defects found during integration testing.

· July 15:

· Fix identified defects and re-test to verify the fixes.

July 17 – July 20: System Testing

· July 17:

· Develop system test cases to cover end-to-end functionality of the weather website.

· Prepare the testing environment for system testing.

· July 19:

· Execute system tests.

· Identify and log any defects found during system testing.

· July 20:

· Fix identified defects and re-test to verify the fixes.

Testing Resources

To run the application and perform comprehensive testing, the following resources will be required:

Personnel

· Dedicated Testers:

· William Nguewa

· Taehoon Song

· Developers: Available to fix defects and provide support during the testing process.

· Tsegent Tekilemariam

Equipment

· Test Devices: Each tester will need a personal computer or laptop capable of running Java 17, an IDE, and multiple browsers for testing purposes.

Software Tools

· Java 17: Ensure that all testers have Java 17 installed, as it is required to run the Spring Boot application.

· Integrated Development Environment (IDE): An IDE such as IntelliJ IDEA or Eclipse for developing, debugging, and running the application.

· Multiple Browsers: Ensure that the application is tested on the latest versions of major browsers, including:

· Google Chrome

· Mozilla Firefox

· Microsoft Edge

Budget

No additional budget is required as all necessary tools and software are open-source and free to use, and existing personal computers or laptops will be utilized for testing purposes.

Execution

· Running the Application: Testers will run the Spring Boot application on their local devices.

· Browser Testing: Testers will open the site on multiple browsers and perform the testing as per the test cases.

By ensuring these resources are in place, the testing team will be well-equipped to conduct thorough and effective testing of the weather website, ensuring it meets all functional and non-functional requirements.

Defect Management

Establishing a robust defect management process is crucial for identifying, reporting, and tracking defects or bugs encountered during testing.

Identifying Defects

· Testing Execution: During the execution of test cases, testers will document any discrepancies between the expected and actual results.

Reporting Defects

· Defect Tracking Tool: Jira

· Defect Report: Each defect will be reported with detailed information to facilitate quick resolution. A standard defect report will include:

· Defect ID: A unique identifier for the defect.

· Summary: A brief description of the defect.

· Description: Detailed information about the defect, including steps to reproduce, expected results, and actual results.

· Priority: The urgency of addressing the defect (e.g., high, medium, low).

· Attachments: Screenshots, logs, or any other relevant files that provide additional context.

Tracking Defects

· Defect Lifecycle: Establish a lifecycle for tracking defects from discovery to resolution. Typical stages include:

· New: The defect has been identified and logged.

· Assigned: The defect has been assigned to a developer for resolution.

· In Progress: The developer is actively working on fixing the defect.

· Fixed: The defect has been resolved and awaits verification.

· Verified: The fix has been verified by a tester.

· Closed: The defect is considered resolved and closed.

· Reopened: If the defect reoccurs, it can be reopened for further investigation.

By following this defect management process, the testing team can efficiently identify, report, and track defects, ensuring timely resolution and contributing to the overall quality and reliability of the weather website.

Summary

This test plan for the weather website outlines a structured approach to ensure the application delivers accurate, reliable, and user-friendly weather information. The testing strategy includes unit testing, integration testing, and system testing, each targeting specific components and interactions within the application. The detailed testing schedule and resource allocation, including Java 17, multiple browsers, and an IDE, provide a clear roadmap for executing comprehensive tests. This approach ensures that each aspect of the website is thoroughly examined and meets the desired quality standards.

A robust defect management process is also established to identify, report, and track issues efficiently. By leveraging the JIRA tool, the testing team can systematically document and resolve defects, ensuring a smooth and reliable user experience. This well-defined testing plan and defect management process contribute to the overall goal of delivering a high-quality weather website that meets user expectations and performs reliably in real-world scenarios.

,

CMSC 495 Phase I Source Code Phase I Source Code

Cover Page

Project Title: Weather Application Project

Team Members:

Introduction

This project is a weather application designed to fetch and display weather information based on a user's zip code. It incorporates various modern technologies and methodologies, including Spring Boot for the backend, HTML, CSS, and JavaScript for the frontend, and integration with the OpenWeatherMap API.

Objective

· Develop a weather application to fetch and display real-time weather data for user-specified locations.

· Provide a detailed weather forecast for the upcoming week.

· Enable users to set alerts for specific weather conditions such as rain, snow, and high temperatures.

Review the Phase I Project Scope

Deliverables:

· A functional weather application with a user-friendly GUI.

· Ability for users to search for weather updates by location.

· Detailed weather forecasts and weather alerts.

Boundaries:

· The application will only support locations that are accessible via the chosen weather API.

· The application will be developed for Java-compatible operating systems only.

Limitations:

· Real-time data accuracy is dependent on the reliability of the weather API service.

· The application will not include advanced features such as radar or satellite imagery.

3. Project Requirements

Functional Requirements:

· Select location and display weather information.

· Set and manage weather alerts.

· Display current weather conditions and forecasts.

Non-functional Requirements:

· The application must have a responsive and intuitive GUI.

· The application should perform data fetching and display updates promptly.

Technical Requirements:

· Operating System: Windows or any Java-compatible OS.

· Application Software: Java JRE.

· Tools: Java Development Kit (JDK), Integrated Development Environment (IDE) such as IntelliJ IDEA or Eclipse, access to a weather API (e.g., OpenWeatherMap).

2. Design the Software Architecture

Architecture Overview

Frontend

· Technologies: HTML, CSS, JavaScript

· Description: This layer is responsible for the user interface and user experience. It consists of HTML for structure, CSS for styling, and JavaScript for interactivity. The frontend communicates with the backend through RESTful APIs.

· Components:

· HTML files for the structure of the web pages

· CSS files for styling and layout

· JavaScript files for handling user interactions and making API requests

· Static images for weather icons based on temperature conditions

Backend

· Technologies: Spring Boot, Java 17, RestTemplate

· Description: This layer handles the business logic of the application. It processes requests from the frontend, interacts with external APIs, and returns the appropriate responses.

· Components:

· WeatherService: A service class that fetches weather data from the OpenWeatherMap API using RestTemplate.

· WeatherController: A REST controller that handles HTTP requests from the frontend and uses WeatherService to get the required data.

Data Layer

· Technologies: H2 Database (in-memory database for simplicity during development)

· Description: This layer is responsible for data storage and retrieval. It stores user preferences, such as saved zip codes, and caches weather data if necessary.

· Components:

· Entities representing the data model, such as WeatherRecord.

· Repositories for CRUD operations on the data.

,

Title: Weather App Project Design

Team Members:

Date: July 2, 2024

Table of Contents

1. Introduction

2. Project Scope

3. Project Requirements

4. Project Methodology

5. Work Breakdown Structure

6. Project Schedule

7. Project Risks

8. Project Evaluation Plan

9. References

1. Introduction

This design document outlines the comprehensive plan for the development of a weather application by Group 4. It includes an analysis of the project’s requirements, a work breakdown of the proposed project, a detailed project schedule, risk management plans, and an evaluation plan.

2. Project Scope

Objectives:

· Develop a weather application to fetch and display real-time weather data for user-specified locations.

· Provide a detailed weather forecast for the upcoming week.

· Enable users to set alerts for specific weather conditions such as rain, snow, and high temperatures.

Deliverables:

· A functional weather application with a user-friendly GUI.

· Ability for users to search for weather updates by location.

· Detailed weather forecasts and weather alerts.

Boundaries:

· The application will only support locations that are accessible via the chosen weather API.

· The application will be developed for Java-compatible operating systems only.

Limitations:

· Real-time data accuracy is dependent on the reliability of the weather API service.

· The application will not include advanced features such as radar or satellite imagery.

3. Project Requirements

Functional Requirements:

· Select location and display weather information.

· Set and manage weather alerts.

· Display current weather conditions and forecasts.

Non-functional Requirements:

· The application must have a responsive and intuitive GUI.

· The application should perform data fetching and display updates promptly.

Technical Requirements:

· Operating System: Windows or any Java-compatible OS.

· Application Software: Java JRE.

· Tools: Java Development Kit (JDK), Integrated Development Environment (IDE) such as IntelliJ IDEA or Eclipse, access to a weather API (e.g., OpenWeatherMap).

4. Project Methodology

Chosen Approach: Agile

Justification: Agile methodology allows for iterative development and frequent reassessment of the project’s direction, which is essential for accommodating the dynamic nature of weather data and user requirements. Regular feedback cycles will enable continuous improvement and ensure that the final product meets user expectations.

5. Work Breakdown Structure (WBS)

1. Project Initiation:

· Meet Team

· Discuss Roles

· Communication Plan

· Discuss Project Options

2. Project Planning:

· Project Plan

· Select Sections

· Execute Sections

· Combine and Submit

3. Design Phase:

· Design

· Config File Load

· Main UI

· User’s UI

4. Functional Requirements

1. API Integration: Integrate with OpenWeatherMap API to fetch real-time weather data.

2. Data Processing: Process and format the weather data to be usable by the frontend.

3. User Authentication: Implement user authentication to manage user-specific settings and preferences.

4. Database Management: Store user data, preferences, and possibly historical weather data for analysis.

Non-Functional Requirements

1. Scalability: Ensure the backend can handle a growing number of users and requests.

2. Security: Secure data transmission and user information with proper authentication and authorization mechanisms.

3. Performance: Optimize the backend to handle API requests and responses with minimal latency.

4. Maintainability: Write clean, modular, and well-documented code for ease of maintenance.

Technology Stack

1. Programming Language: Java

2. Framework: Spring Boot

3. Database: SQL

4. API Client: RestTemplate (Spring Boot)

5. Authentication: Spring Security with JWT

4. Phase 1 Build

1. Config File Load

· Frontend: Set up configuration files for UI themes, localization, and initial settings.

· Backend:

· Load configuration files for database connections, API keys, and other environment-specific settings.

· Implement Spring Boot configuration properties to manage different environments.

2. Main UI

· Frontend:

· Design and implement the main user interface using JavaFX.

· Ensure the main UI includes essential components such as the weather display, search bar, and navigation menu.

· Backend:

· Develop core API endpoints in Spring Boot to fetch weather data.

· Implement the logic to call OpenWeatherMap API and process the responses.

· Set up initial database schema using PostgreSQL to store user preferences and weather data.

Phase 2 Build

1. User’s UI

· Frontend:

· Create user-specific interfaces, including login, registration, and profile management screens.

· Implement functionality for users to save their settings and preferences.

· Backend:

· Implement user authentication and authorization using Spring Security and JWT.

· Develop endpoints for user management, including registration, login, and profile updates.

· Create database tables for user information and implement CRUD operations.

Phase 3 Build

1. Final Compilation of All Units

· Frontend:

· Integrate all UI components and ensure seamless navigation between different screens.

· Conduct thorough testing of the entire frontend to ensure functionality and responsiveness.

· Backend:

· Finalize and optimize all API endpoints.

· Ensure all data processing and storage mechanisms are functioning correctly.

· Perform load testing and optimize the backend for performance.

· Deploy the backend to a cloud service (e.g., AWS, Heroku) and ensure it is accessible by the frontend.

Combined Tasks

1. API Endpoint Development

· Develop RESTful endpoints in Spring Boot to serve data to the frontend.

· Ensure endpoints are secure and follow REST best practices.

2. Frontend-Backend Integration

· Implement API calls in the frontend to retrieve data from the backend.

· Ensure seamless data flow between the frontend and backend.

3. Testing

· Conduct end-to-end testing to ensure that the frontend and backend work together as expected.

· Identify and fix any integration issues.

5. Testing Phase:

· Use Guide/Test Plan

· Individual Test Plans

· First Draft (Test Plans)

· Individual User Guides

· First Draft (User Guide)

· Final Draft (Test Plan)

· Final Draft (User Guide)

6. Project Schedule

Development Schedule with Milestones (June – August 2024):

Week

Activity

1 (08/04/2024)

Meet Team

2 (08/04/2024)

Discuss roles, Communication plan

3 (08/04/2024)

Project Plan, Select sections

4 (08/04/2024)

Execute sections, Combine and submit

5 (08/04/2024)

Use Guide/Test Plan, Individual Test Plans

6 (08/10/2024)

First Draft (Test Plans), Individual User Guides

7 (08/10/2024)

Final Draft (Test Plan), Final Draft (User Guide)

8 (08/10/2024)

Design, Config File Load, Main UI

9 (08/12/2024)

Phase 1 Build

10 (08/21/2024)

Phase 2 Build

11 (08/30/2024)

Phase 3 Build, Testing

7. Project Risks

Potential Risks:

· API Reliability: Dependency on the weather API service for real-time data.

· Development Delays: Potential delays in meeting development milestones.

· Technical Challenges: Integration issues between different modules of the application.

Mitigation Strategies:

· API Reliability: Research and select a robust and reliable weather API with high uptime.

· Development Delays: Implement a buffer in the schedule for unforeseen delays and regularly track progress.

· Technical Challenges: Regular team meetings to address and resolve technical issues promptly.

8. Project Evaluation Plan

Evaluation Criteria:

· Functionality: Ensure all features (location search, weather display, alert settings) work as intended.

· Performance: The application should fetch and display data promptly without lag.

· User Interface: The GUI should be user-friendly and intuitive.

· Reliability: The application should handle errors gracefully and provide meaningful feedback to the user.

· Documentation: Comprehensive user guides and test plans should be available.

Evaluation Methods:

· Testing: Conduct unit testing, integration testing, and user acceptance testing.

· User Feedback: Collect feedback from a sample of target users and incorporate improvements.

· Review: Regular project reviews to assess progress against milestones and make necessary adjustments.

9. References

· OpenWeatherMap. (n.d.). OpenWeatherMap API documentation. Retrieved from https://openweathermap.org/api

· Oracle. (n.d.). JavaFX documentation. Retrieved from https://docs.oracle.com/javase/8/javase-clienttechnologies.htm

· Agile Alliance. (n.d.). Agile 101. Retrieved from https://www.agilealliance.org/agile101/