Subversion Repositories ES

Rev

Rev 17 | Go to most recent revision | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed

1
/**
 *
 */

package de.pointedears.converter.net;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import de.pointedears.converter.R;
import de.pointedears.converter.app.CurrenciesActivity;
import de.pointedears.converter.db.ConversionData;
import de.pointedears.converter.helpers.ConverterThread;
import de.pointedears.converter.helpers.UpdateService;

/**
 * @author pelinux
 *
 */

public class RatesUpdater implements Runnable
{
  /*
   * XML markup attributes
   */

  private static final String ATTR_RATE = "rate"; //$NON-NLS-1$
  private static final String ATTR_CURRENCY = "currency"; //$NON-NLS-1$
  private static final String ATTR_TIME = "time"; //$NON-NLS-1$

  private static final String URL_ECB =
    "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"; //$NON-NLS-1$

  private final CurrenciesActivity activityContext;
  private ConverterThread updateThread = null;

  private final UpdateService service;

  /**
   * @param activityContext
   *          The activityContext for this updater.
   *          FIXME: Required only for database access
   * @param updateService
   *          The service that started this updater
   */

  public RatesUpdater(CurrenciesActivity activityContext,
    UpdateService updateService)
  {
    this.activityContext = activityContext;
    this.service = updateService;
  }

  /**
   * @return the updateThread
   */

  public ConverterThread getUpdateThread()
  {
    return this.updateThread;
  }

  /**
   * @param updateThread
   *          the thread that this updater is running in
   */

  public void setUpdateThread(ConverterThread updateThread)
  {
    this.updateThread = updateThread;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Runnable#run()
   */

  @Override
  public void run()
  {
    int len = 0;
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
    Date updated = new Date();

    if (this.getUpdateThread() != null)
    {
      TextView textUpdating =
        (TextView) this.activityContext
          .findViewById(R.id.currencies_text_updating);
      textUpdating.setVisibility(View.VISIBLE);

      DocumentBuilderFactory documentBuilderFactory =
        DocumentBuilderFactory.newInstance();
      documentBuilderFactory.setNamespaceAware(true);
      DocumentBuilder builder;
      try
      {
        builder = documentBuilderFactory.newDocumentBuilder();
        Document doc;
        try
        {
          doc = builder.parse(RatesUpdater.URL_ECB);
          XPathFactory xpathFactory = XPathFactory.newInstance();
          XPath xpath = xpathFactory.newXPath();
          // NamespaceContextHelper namespaceContext =
          // new NamespaceContextHelper();
          // namespaceContext.add("gesmes",
          // "http://www.gesmes.org/xml/2002-08-01");
          // xpath.setNamespaceContext(namespaceContext);

          try
          {
            /*
             * FIXME: Why doesn't a simple "./Cube/Cube/Cube" work even with a
             * namespace resolver?
             */

            @SuppressWarnings("nls")
            XPathExpression expr =
              xpath
                .compile("./*[local-name() = 'Cube']/*[local-name() = 'Cube']");
            NodeList nodes = (NodeList)
              expr.evaluate(doc.getDocumentElement(), XPathConstants.NODESET);
            Element parentCube = (Element) nodes.item(0);
            if (parentCube == null)
            {
              return;
            }

            try
            {
              updated =
                df.parse(parentCube.getAttribute(RatesUpdater.ATTR_TIME));
            }
            catch (ParseException e)
            {
              Log.e(this.getClass().toString(),
                "Could not parse the `time' attribute into a Date", e); //$NON-NLS-1$
            }

            expr =
              xpath
                .compile("./*[local-name()='Cube' and (@currency='CHF' or @currency='USD')]"); //$NON-NLS-1$
            nodes =
              (NodeList) expr.evaluate(parentCube, XPathConstants.NODESET);
            NodeList childCubes = nodes;

            len = childCubes.getLength();

            HashMap<String, ConversionData> conversionRates =
              this.activityContext.getConversionRates();
            for (int i = 0; i < len; ++i)
            {
              Element item = (Element) childCubes.item(i);
              String currency = item.getAttribute(RatesUpdater.ATTR_CURRENCY);

              try
              {
                Double rate =
                  Double.parseDouble(item.getAttribute(RatesUpdater.ATTR_RATE));
                conversionRates
                  .put(currency, new ConversionData(rate, updated));
              }
              catch (NumberFormatException e)
              {

              }
            }

            this.activityContext.getDatabase().writeConversionsToDatabase(null);
          }
          catch (XPathExpressionException e)
          {
            Log.e(this.getClass().toString(), "Error in XPath expression", e); //$NON-NLS-1$
          }
        }
        catch (SAXException e)
        {
          Log.e(this.getClass().toString(),
            "Exception while parsing external XML resource", e); //$NON-NLS-1$
        }
        catch (IOException e)
        {
          Log.e(this.getClass().toString(),
            "I/O exception while parsing external XML resource", e); //$NON-NLS-1$
        }
      }
      catch (ParserConfigurationException e)
      {
        Log.e(this.getClass().toString(),
          "Document builder cannot be created", e); //$NON-NLS-1$
      }

      if (len > 0)
      {
        /*
         * Notify the activity that we are done (causes a notification to be
         * shown)
         */

        Intent intent = new Intent(UpdateService.ACTION_UPDATE);
        intent.putExtra(UpdateService.EXTRA_NUM_RATES, len);
        intent.putExtra(UpdateService.EXTRA_DATE, updated);
        this.service.sendBroadcast(intent);
      }

      textUpdating.setVisibility(View.GONE);
    }
  }
}