Solr: własna implementacja ExchangeRateProvider dla CurrencyField

W poprzednim wpisie dotyczącym implementacji własnych funkcjonalności Solr pokazałem, jak zaimplementować własny filtr dla Solr. Dzisiaj zaimplementujemy własny mechanizm dostarczający kursów wymiany walut, czyli ExchangeRateProvider dla nowego typu pól – CurrencyField zaprezentowany w Solr 3.6.

Założenia

Aby pokazać, w jaki sposób zaimplementować własny provider dla typu CurrencyField zakładam, iż nasza aplikacja, która korzysta z Solr jest w stanie dostarczyć kursy w odpowiedniej formie. W tym celu zakładam, iż posiadamy bibliotekę, która udostępnia klasę implementującą następujący interfejs:

package pl.solr;

import java.util.List;

public interface UpToDateCurrencyProvider {
  Map<String, List<Currency>> getExchangeRates();
  void refresh();
  void initialize();
}

A klasa Currency wygląda następująco:

package pl.solr;

public class Currency {
  private String from;
  private String to;
  private double rate;

  public Currency(String from, String to, double rate) {
    this.from = from;
    this.to = to;
    this.rate = rate;
  }

  public String getFrom() {
    return from;
  }

  public String getTo() {
    return to;
  }

  public double getRate() {
    return rate;
  }
}

Podobnie, jak w poprzednim wpisie, pozwolę sobie pominąć szczegóły konfiguracji środowiska, budowania archiwum jar i tego typu szczegóły. Oprócz tego, założenie jest takie, aby nie komplikować kodu i skupić się na najważniejszym, czyli implementacji SolrPLCurrencyExchangeProvider.

Implementacja SolrPLExchangeRateProvider

package pl.solr;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.solr.common.ResourceLoader;
import org.apache.solr.common.SolrException;
import org.apache.solr.schema.ExchangeRateProvider;

public class SolrPLCurrencyExchangeProvider implements ExchangeRateProvider {
  private UpToDateCurrencyProvider provider;

  @Override
  public double getExchangeRate(String sourceCurrencyCode, String targetCurrencyCode) throws SolrException {
    if (sourceCurrencyCode == null || targetCurrencyCode == null) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Cannot get exchange rate - source or target currency was null.");
    }
    List<Currency> exchangesRates = provider.getExchangeRates().get(sourceCurrencyCode);
    if (exchangesRates == null) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Cannot get exchange rate - source currency exchange rates not found");
    }
    Currency exchange = null;
    for (Currency currency : exchangesRates) {
      if (currency.getTo().compareTo(targetCurrencyCode) == 0) {
        exchange = currency;
        break;
      }
    }
    if (exchange == null) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Cannot get exchange rate - target currency exchange rates not found");
    }
    return exchange.getRate();
  }

  @Override
  public void inform(ResourceLoader loader) throws SolrException {
    this.provider = new SolrPLUpToDateCurrencyProvider();
    this.provider.initialize();
    reload();
  }

  @Override
  public void init(Map<String, String> args) {
  }

  @Override
  public Set<String> listAvailableCurrencies() {
    return provider.getExchangeRates().keySet();
  }

  @Override
  public boolean reload() throws SolrException {
    provider.refresh();
    return true;
  }
}

Drobne wyjaśnienia dotyczące implementacji

Kilka słów wyjaśnienia, do implementacji pokazanej powyżej:

  • Linia 11 – tworzymy klasę implementującą interfejs ExchangeRateProvider z pakietu org.apache.solr.schema.
  • Linia 12 – mechanizm, który umożliwi nam pobieranie kursów wymiany.
  • Linia 15 – methoda getExchangeRate, czyli główna metoda naszego providera, w której pobieramy dane z naszego serwisu i zwracamy wartość double.
  • Linia 19 – pobranie dostępnych danych dotyczących wymiany. W produkcyjnym systemie należałoby te dane cache’ować. W tym przykładzie tego nie robimy, aby uprościć kod.
  • Linie 24 – 29 – pętla w której szukamy interesujących nas danych dotyczących kursu wymiany.
  • Linie 30 – 32 – jeżeli nie znaleźliśmy kursu wymiany, rzucamy wyjątek.
  • Linie 37 – 41 – tworzymy nasz serwis wymiany walut w metodzie inform oraz go inicjalizujemy.
  • Linie 48 – 50 – implementacja metody zwracającej dostępne kursy wymiany.
  • Linie 53 – 56 – implementacja metody odświeżającej kursy wymiany.

Konfiguracja

Po skompilowaniu i przygotowaniu biblioteki w formacie jar, kopiujemy ją do katalogu, gdzie Solr będzie ją widział. Możemy to uzyskać np. tworząc katalog lib w katalogu domowym Solr, a następnie dodać odpowiedni wpis do pliku solrconfig.xml, np. taki:

<lib dir="../lib/" regex="*.jar" />

Następnie zmieniamy plik schema.xml dodając typ oparty o solr.CurrencyField, na przykład w następujący sposób:

<fieldType class="solr.CurrencyField" name="currencyField" defaultCurrency="USD" providerClass="pl.solr.SolrPLExchangeRateProvider" />

Podsumowanie

Największym problemem podczas implementacji ExchangeRateProvider jest tak naprawdę dostarczenie interesujących nas danych, czyli informacji na temat kursów wymiany. Reszta, jak widać w powyższym przykładzie, nie jest mocno skomplikowana. Mam nadzieje, że tak jak poprzedni wpis, tak i ten, przyda się komuś kiedyś i oszczędzi mu kilku cennych godzin 🙂 Oczywiście powyższy przykład pobiera dane przy każdym odwołaniu, można to zoptymalizować dodając cache i odpowiedni czas ważności tych danych.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *