/** * */ 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 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); } } }