Rafal Kuc is a team leader and software developer. Right now he is a software architect and Solr and Lucene specialist. Mainly focused on Java, but open on every tool and programming language that will make the achievement of his goal easier and faster. Rafal is also one of the founders of solr.pl site where he tries to share his knowledge and help people with their problems. Rafał is a DZone MVB and is not an employee of DZone and has posted 75 posts at DZone. You can read more from them at their website. View Full User Profile

Developing Your Own ExchangeRateProvider for CurrencyField Type

06.28.2012
| 4340 views |
  • submit to reddit

In the previous entry showing how to develop custom Solr functionalities we are showing how to implement your own Solr filter. Today I’ll show you how to implement your own exchange rate provider, so we will implement the  ExchangeRateProvider for the CurrencyField type introduced in Solr 3.6.

Assumptions

In order to show how to implement your own provider for the CurrencyField type, I assume that our application which uses Solr is able to provide exchange rates in the proper form. So, I assume we have a library which provided implementation for the following interface:

package pl.solr;

import java.util.List;

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

 And the Currency class looks like this:

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;
  }
}

Similar to the previous development entry I’ll omit the details about IDE and jar building. We will focus on the most interesting stuff – the implementation of SolrPLCurrencyExchangeProvider.

SolrPLExchangeRateProvider Implementation

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;
  }
}

Some Explanations

Some explanations regarding the above code:

  • Linia 11 – we create a class that implements ExchangeRateProvider interface from org.apache.solr.schema package.
  • Linia 12 – our service, which provides exchange rates.
  • Linia 15getExchangeRate method implementation which gets the data from the provided service and returns double value.
  • Linia 19 – get the data regarding the exchange rates. In the production environment we would like to cache this data from some period of time. We don’t do it in the example to simplify the code.
  • Linie 24 – 29 – loop in which we choose the correct Currency object.
  • Linie 30 – 32 – we throw an exception, when proper Currency object wasn’t found.
  • Linie 37 – 41 – we create an instance of our service in the inform method and we initialize it.
  • Linie 48 – 50 – method returning all the available exchange rates.
  • Linie 53 – 56 – method refreshing the provider.

Configuration

After compilation and jar file preparation, we copy the jar file to a directory where Solr will see it. For example, we can create a lib directory in Solr home directory and then add the following entry to solrconfig.xml file:

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

 We also need to change the schema.xml file and add a type based on solr.CurrencyField, for example:

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

Summary

The main problem with implementing your own ExchangeRateProvider is the data, not the actual implementation as you can see in the above example. I hope that this entry will help some of you and let you save some precious time ;) Of course, you should remember that this is only an simplified example and we omit the exchange rates cache for example, which should be present in a code you want to use in the production system.

Published at DZone with permission of Rafał Kuć, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: