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.