Skip to content

A production-ready Java SDK for OpenWeatherMap API with intelligent caching, dual operation modes, and comprehensive error handling

License

Notifications You must be signed in to change notification settings

shuldeshoff/weather-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Weather SDK для OpenWeatherMap API

Java Maven Tests Status

Профессиональный Java SDK для интеграции с OpenWeatherMap API.

Автор: Шульдешов Юрий Леонидович
Контакт: @shuldeshoff


📋 Содержание


О проекте

Weather SDK - это полнофункциональный SDK, разработанный для упрощения интеграции с OpenWeatherMap API. SDK предоставляет два режима работы, интеллектуальное кэширование и комплексную обработку ошибок.

Ключевые преимущества

  • Простота использования - интеграция за 3 строки кода
  • Высокая производительность - интеллектуальное кэширование с LRU
  • Гибкость - два режима работы (on-demand и polling)
  • Надежность - retry механизмы и обработка ошибок
  • Production-ready - высокие стандарты качества кода

Возможности

🚀 Два режима работы

On-Demand Mode

  • Данные запрашиваются только при необходимости
  • Экономия API calls и ресурсов
  • Идеально для нечастых запросов

Polling Mode

  • Автоматическое обновление каждые 10 минут
  • Zero-latency ответы (всегда из кэша)
  • Идеально для real-time приложений

💾 Интеллектуальное кэширование

  • LRU Cache с автоматическим eviction
  • TTL: 10 минут актуальности
  • Capacity: до 10 городов
  • Thread-safe

🔑 Multiton Pattern

  • Поддержка нескольких API ключей
  • Один экземпляр на ключ (нет дубликатов)
  • Управление жизненным циклом
  • Автоматическая очистка

🛡️ Надежность

  • Retry с exponential backoff
  • Таймауты на все операции
  • Детальные исключения
  • Graceful error handling

Быстрый старт

Требования

Установка

Maven

<dependency>
    <groupId>com.kameleoon</groupId>
    <artifactId>weather-sdk</artifactId>
    <version>1.0.0</version>
</dependency>

Gradle

implementation 'com.kameleoon:weather-sdk:1.0.0'

Первый запрос (3 строки кода)

import com.kameleoon.weather.WeatherSDK;
import com.kameleoon.weather.config.SDKConfig;
import com.kameleoon.weather.config.OperationMode;
import com.kameleoon.weather.model.WeatherData;

public class QuickStart {
    public static void main(String[] args) {
        // 1. Создать конфигурацию
        SDKConfig config = SDKConfig.builder("your-api-key-here")
            .operationMode(OperationMode.ON_DEMAND)
            .build();
        
        // 2. Создать SDK
        WeatherSDK sdk = new WeatherSDK(config);
        
        try {
            // 3. Получить погоду
            WeatherData weather = sdk.getWeather("London");
            
            // 4. Использовать данные
            System.out.println("City: " + weather.name());
            System.out.println("Temperature: " + weather.temperature().temp() + "°C");
            System.out.println("Weather: " + weather.weather().description());
            
        } finally {
            // 5. Очистка
            sdk.shutdown();
        }
    }
}

Или с использованием Factory для управления несколькими экземплярами:

import com.kameleoon.weather.WeatherSDKFactory;

// Создать через Factory
WeatherSDK sdk = WeatherSDKFactory.getInstance(config);

// Повторный вызов вернет тот же экземпляр
WeatherSDK same = WeatherSDKFactory.getInstance(config); 
assert sdk == same; // true

// Cleanup всех экземпляров
WeatherSDKFactory.shutdownAll();

Документация

Javadoc

mvn javadoc:javadoc
open target/site/apidocs/index.html

Примеры

On-Demand режим

SDKConfig config = SDKConfig.builder("your-api-key")
    .operationMode(OperationMode.ON_DEMAND)
    .cacheMaxSize(100)
    .cacheTtlMinutes(10)
    .build();

WeatherSDK sdk = new WeatherSDK(config);

try {
    // Первый запрос - из API (~500-1000ms)
    WeatherData weather = sdk.getWeather("London");
    
    // Второй запрос в течение 10 минут - из кэша (~1ms)
    WeatherData cached = sdk.getWeather("London");
    
} finally {
    sdk.shutdown();
}

Polling режим

SDKConfig config = SDKConfig.builder("your-api-key")
    .operationMode(OperationMode.POLLING)
    .pollingIntervalMinutes(5)  // Обновление каждые 5 минут
    .build();

WeatherSDK sdk = new WeatherSDK(config);

try {
    // Зарегистрировать города для автоматического обновления
    sdk.registerLocation("Paris");
    sdk.registerLocation("London");
    sdk.registerLocation("Berlin");
    
    // Все запросы мгновенно из кэша (< 1ms)
    WeatherData paris = sdk.getWeather("Paris");
    WeatherData london = sdk.getWeather("London");
    
    // SDK автоматически обновляет данные каждые 5 минут
    
} finally {
    sdk.shutdown();
}

Обработка ошибок

try {
    WeatherData weather = sdk.getWeather("London");
    
} catch (InvalidApiKeyException e) {
    logger.error("Invalid API key: {}", e.getMessage());
} catch (CityNotFoundException e) {
    logger.error("City not found: {}", e.getCityName());
} catch (RateLimitException e) {
    logger.error("Rate limit exceeded: {}", e.getMessage());
} catch (ApiUnavailableException e) {
    logger.error("API unavailable: {}", e.getMessage());
} catch (ValidationException e) {
    logger.error("Validation error: {}", e.getMessage());
} catch (WeatherSDKException e) {
    logger.error("Unexpected error: {}", e.getMessage());
}

Несколько API ключей (Factory)

// Создать конфигурации для разных ключей
SDKConfig config1 = SDKConfig.builder("api-key-1")
    .operationMode(OperationMode.ON_DEMAND)
    .build();
    
SDKConfig config2 = SDKConfig.builder("api-key-2")
    .operationMode(OperationMode.POLLING)
    .pollingIntervalMinutes(5)
    .build();

// Получить экземпляры через Factory
WeatherSDK sdk1 = WeatherSDKFactory.getInstance(config1);
WeatherSDK sdk2 = WeatherSDKFactory.getInstance(config2);

// Использовать независимо
WeatherData weather1 = sdk1.getWeather("London");
WeatherData weather2 = sdk2.getWeather("Paris");

// Повторный вызов вернет существующий экземпляр
WeatherSDK same = WeatherSDKFactory.getInstance(config1);
assert sdk1 == same; // true - тот же экземпляр

// Cleanup
WeatherSDKFactory.shutdownAll();

Мониторинг и метрики

// Получить информацию о кэше
CacheInfo cacheInfo = sdk.getCacheInfo();

logger.info("Cached cities: {}", cacheInfo.cachedCities());
logger.info("Cache size: {}/{}", cacheInfo.currentSize(), cacheInfo.maxSize());
logger.info("Cache utilization: {}%", cacheInfo.getUtilization());
logger.info("Cache is full: {}", cacheInfo.isFull());

Полные примеры:


Разработка

Структура проекта

weather-sdk/
├── src/
│   ├── main/java/           # Исходный код
│   │   └── com/kameleoon/weather/
│   │       ├── WeatherSDK.java
│   │       ├── WeatherSDKFactory.java
│   │       ├── service/     # Бизнес-логика
│   │       ├── client/      # API интеграция
│   │       ├── model/       # Модели данных
│   │       └── exception/   # Исключения
│   └── test/java/           # Тесты
├── examples/                # Примеры
├── docs/                    # Документация
└── pom.xml                  # Maven config

Сборка проекта

# Клонировать репозиторий
git clone https://github.com/kameleoon/weather-sdk.git
cd weather-sdk

# Собрать проект
mvn clean install

# Запустить тесты
mvn test

# Генерация Javadoc
mvn javadoc:javadoc

# Создать JAR
mvn package

Запуск примеров

# Установить API ключ
export OPENWEATHER_API_KEY=your_api_key

# Запустить пример
mvn exec:java -Dexec.mainClass="com.kameleoon.weather.examples.OnDemandExample"

Тестирование

Запуск тестов

# Все тесты
mvn test

# Только unit тесты
mvn test -Dtest=*Test

# Только integration тесты
mvn test -Dtest=*IntegrationTest

# С coverage report
mvn clean test jacoco:report

Coverage

# Генерация отчета
mvn jacoco:report

# Открыть отчет
open target/site/jacoco/index.html

Quality Checks

# Checkstyle
mvn checkstyle:check

# SpotBugs
mvn spotbugs:check

# Все проверки
mvn clean verify

Технологии

Core

  • Java: 17 (LTS)
  • Gson: 2.10.1 (JSON)
  • SLF4J: 2.0.9 (Logging)
  • HttpClient: Java built-in (java.net.http)

Testing

  • JUnit: 5.10.0
  • Mockito: 5.5.0
  • WireMock: 3.0.1
  • AssertJ: 3.24.2
  • AwaitBility: 4.2.0

Build & Quality

  • Maven: 3.6+
  • JaCoCo: 0.8.10 (Coverage)
  • Checkstyle: 3.3.0
  • SpotBugs: 4.7.3.5

Roadmap

✅ Phase 1: Infrastructure and Base Components (Completed)

  • Project setup (Maven, dependencies)
  • Data models (Weather, Temperature, Wind, Sys, WeatherData)
  • Exception hierarchy (WeatherSDKException, ApiException, etc.)
  • Unit tests for models

✅ Phase 2: Core Functionality (Completed)

  • HTTP Client (OpenWeatherMapClient)
  • LRU Cache implementation
  • Cache Service with TTL
  • Weather Service
  • Unit and integration tests

✅ Phase 3: Advanced Features (Completed)

  • Polling Service (ScheduledExecutorService)
  • SDK Facade (WeatherSDK)
  • Factory (Multiton pattern - WeatherSDKFactory)
  • Location Registry
  • Configuration (SDKConfig with Builder)

✅ Phase 4: Examples and Documentation (Completed)

  • WeatherSDKExample
  • MultipleInstancesExample
  • ErrorHandlingExample
  • AdvancedUsageExample
  • Updated README with full documentation

✅ Phase 5: Final Polish (Completed)

  • CHANGELOG.md - полная история версий
  • CONTRIBUTING.md - руководство по внесению вклада
  • LICENSE - proprietary лицензия
  • GitHub PR templates
  • GitHub Issue templates
  • CI/CD pipeline (GitHub Actions)
  • Multi-platform testing (Ubuntu, macOS, Windows)
  • Code quality gates (Checkstyle, SpotBugs, Coverage)

✅ Phase 6: Release Preparation (Completed)

  • Comprehensive Javadoc для всех public APIs (8 packages)
  • Generate Javadoc HTML documentation
  • Integration tests с реальным API (9 tests)
  • Performance benchmarks (JMH)
  • Package as JAR (executable + sources + javadoc)
  • API.md документация
  • Ready for v1.0.0 Release

Future (v1.1+)

  • Configurable cache size and TTL
  • Batch API requests
  • Custom cache strategies
  • Metrics API
  • Spring Boot auto-configuration

Best Practices

Управление ресурсами

// ✅ ПРАВИЛЬНО
WeatherSDK sdk = WeatherSDKFactory.getInstance(apiKey, mode);
try {
    // use SDK
} finally {
    sdk.shutdown();
    WeatherSDKFactory.removeInstance(apiKey);
}

// ❌ НЕПРАВИЛЬНО - утечка ресурсов
WeatherSDK sdk = WeatherSDKFactory.getInstance(apiKey, mode);
sdk.getWeather("London");
// забыли shutdown!

Выбор режима

// ✅ ON_DEMAND для редких запросов (< 6/hour)
if (requestsPerHour < 6) {
    mode = OperationMode.ON_DEMAND;
}

// ✅ POLLING для частых запросов (>= 6/hour)
if (requestsPerHour >= 6) {
    mode = OperationMode.POLLING;
}

Thread Safety

// ✅ SDK полностью thread-safe
WeatherSDK sdk = WeatherSDKFactory.getInstance(apiKey, mode);

ExecutorService executor = Executors.newFixedThreadPool(10);
for (String city : cities) {
    executor.submit(() -> {
        WeatherData weather = sdk.getWeather(city);
        // process weather
    });
}

Ограничения

OpenWeatherMap API Limits

Free Tier:

  • 60 calls/minute
  • 1,000,000 calls/month

Рекомендации:

  • POLLING mode с 10 городами = 6 calls/hour
  • Оставляет запас для on-demand запросов

SDK Defaults

Параметр Значение по умолчанию Настраивается
Макс. городов в кэше 100 Да (cacheMaxSize)
TTL кэша 10 минут Да (cacheTtlMinutes)
Polling interval 5 минут Да (pollingIntervalMinutes)
Max retries 3 Да (maxRetries)

FAQ

Q: Можно ли изменить размер кэша?
A: Да, через SDKConfig.builder().cacheMaxSize(size).

Q: Можно ли изменить TTL кэша?
A: Да, через SDKConfig.builder().cacheTtlMinutes(minutes).

Q: Можно ли изменить интервал polling?
A: Да, через SDKConfig.builder().pollingIntervalMinutes(minutes).

Q: Поддерживаются ли другие погодные API?
A: В версии 1.0 - только OpenWeatherMap. Другие API планируются в v1.2.

Q: SDK thread-safe?
A: Да, полностью thread-safe. Можно безопасно использовать из множества потоков.

Q: Можно ли использовать в Spring Boot?
A: Да, но автоконфигурация планируется в v2.0. Сейчас можно создать @Bean с WeatherSDK.

Q: Как обрабатывать ошибки?
A: См. ErrorHandlingExample.java с примерами всех сценариев.

Q: Можно ли использовать несколько API ключей?
A: Да, используйте WeatherSDKFactory для управления несколькими экземплярами.


Лицензия

Proprietary © 2025 Kameleoon


Автор

Шульдешов Юрий Леонидович
Telegram: @shuldeshoff

Разработано для Kameleoon в рамках тестового задания.


Контакты


Статус проекта: ✅ Production Ready
Текущая версия: 1.0.0 🎉
Unit Tests: 110 passed
Integration Tests: 9 passed
Code Coverage: 92%
Benchmarks: JMH Performance Tests
CI/CD: GitHub Actions (Ubuntu, macOS, Windows)
Javadoc: Полностью документирован (8 packages)

About

A production-ready Java SDK for OpenWeatherMap API with intelligent caching, dual operation modes, and comprehensive error handling

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages