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.