Rev 17 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
16 | PointedEar | 1 | /** |
2 | * |
||
3 | */ |
||
4 | package de.pointedears.converter.net; |
||
5 | |||
6 | import java.io.IOException; |
||
17 | PointedEar | 7 | import java.text.DateFormat; |
8 | import java.text.ParseException; |
||
9 | import java.text.SimpleDateFormat; |
||
10 | import java.util.Date; |
||
11 | import java.util.HashMap; |
||
16 | PointedEar | 12 | |
13 | import javax.xml.parsers.DocumentBuilder; |
||
14 | import javax.xml.parsers.DocumentBuilderFactory; |
||
15 | import javax.xml.parsers.ParserConfigurationException; |
||
16 | import javax.xml.xpath.XPath; |
||
17 | import javax.xml.xpath.XPathConstants; |
||
18 | import javax.xml.xpath.XPathExpression; |
||
19 | import javax.xml.xpath.XPathExpressionException; |
||
20 | import javax.xml.xpath.XPathFactory; |
||
21 | |||
22 | import org.w3c.dom.Document; |
||
17 | PointedEar | 23 | import org.w3c.dom.Element; |
16 | PointedEar | 24 | import org.w3c.dom.NodeList; |
25 | import org.xml.sax.SAXException; |
||
26 | |||
27 | import android.content.Intent; |
||
17 | PointedEar | 28 | import android.util.Log; |
29 | import android.view.View; |
||
30 | import android.widget.TextView; |
||
16 | PointedEar | 31 | import de.pointedears.converter.R; |
17 | PointedEar | 32 | import de.pointedears.converter.app.CurrenciesActivity; |
33 | import de.pointedears.converter.db.ConversionData; |
||
16 | PointedEar | 34 | import de.pointedears.converter.helpers.ConverterThread; |
17 | PointedEar | 35 | import de.pointedears.converter.helpers.UpdateService; |
16 | PointedEar | 36 | |
37 | /** |
||
38 | * @author pelinux |
||
39 | * |
||
40 | */ |
||
41 | public class RatesUpdater implements Runnable |
||
42 | { |
||
18 | PointedEar | 43 | /* |
44 | * XML markup attributes |
||
45 | */ |
||
46 | private static final String ATTR_RATE = "rate"; //$NON-NLS-1$ |
||
47 | private static final String ATTR_CURRENCY = "currency"; //$NON-NLS-1$ |
||
48 | private static final String ATTR_TIME = "time"; //$NON-NLS-1$ |
||
49 | |||
16 | PointedEar | 50 | private static final String URL_ECB = |
51 | "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"; //$NON-NLS-1$ |
||
52 | |||
17 | PointedEar | 53 | private final CurrenciesActivity activityContext; |
16 | PointedEar | 54 | private ConverterThread updateThread = null; |
55 | |||
17 | PointedEar | 56 | private final UpdateService service; |
57 | |||
16 | PointedEar | 58 | /** |
18 | PointedEar | 59 | * @param activityContext |
60 | * The activityContext for this updater. |
||
61 | * FIXME: Required only for database access |
||
17 | PointedEar | 62 | * @param updateService |
18 | PointedEar | 63 | * The service that started this updater |
16 | PointedEar | 64 | */ |
17 | PointedEar | 65 | public RatesUpdater(CurrenciesActivity activityContext, |
66 | UpdateService updateService) |
||
16 | PointedEar | 67 | { |
68 | this.activityContext = activityContext; |
||
17 | PointedEar | 69 | this.service = updateService; |
16 | PointedEar | 70 | } |
71 | |||
72 | /** |
||
73 | * @return the updateThread |
||
74 | */ |
||
75 | public ConverterThread getUpdateThread() |
||
76 | { |
||
77 | return this.updateThread; |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * @param updateThread |
||
18 | PointedEar | 82 | * the thread that this updater is running in |
16 | PointedEar | 83 | */ |
84 | public void setUpdateThread(ConverterThread updateThread) |
||
85 | { |
||
86 | this.updateThread = updateThread; |
||
87 | } |
||
88 | |||
89 | /* |
||
90 | * (non-Javadoc) |
||
91 | * |
||
92 | * @see java.lang.Runnable#run() |
||
93 | */ |
||
94 | @Override |
||
95 | public void run() |
||
96 | { |
||
17 | PointedEar | 97 | int len = 0; |
98 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ |
||
99 | Date updated = new Date(); |
||
100 | |||
16 | PointedEar | 101 | if (this.getUpdateThread() != null) |
102 | { |
||
17 | PointedEar | 103 | TextView textUpdating = |
104 | (TextView) this.activityContext |
||
105 | .findViewById(R.id.currencies_text_updating); |
||
106 | textUpdating.setVisibility(View.VISIBLE); |
||
16 | PointedEar | 107 | |
108 | DocumentBuilderFactory documentBuilderFactory = |
||
109 | DocumentBuilderFactory.newInstance(); |
||
110 | documentBuilderFactory.setNamespaceAware(true); |
||
17 | PointedEar | 111 | DocumentBuilder builder; |
16 | PointedEar | 112 | try |
113 | { |
||
17 | PointedEar | 114 | builder = documentBuilderFactory.newDocumentBuilder(); |
115 | Document doc; |
||
16 | PointedEar | 116 | try |
117 | { |
||
17 | PointedEar | 118 | doc = builder.parse(RatesUpdater.URL_ECB); |
16 | PointedEar | 119 | XPathFactory xpathFactory = XPathFactory.newInstance(); |
120 | XPath xpath = xpathFactory.newXPath(); |
||
121 | // NamespaceContextHelper namespaceContext = |
||
122 | // new NamespaceContextHelper(); |
||
123 | // namespaceContext.add("gesmes", |
||
124 | // "http://www.gesmes.org/xml/2002-08-01"); |
||
125 | // xpath.setNamespaceContext(namespaceContext); |
||
126 | |||
127 | try |
||
128 | { |
||
129 | /* |
||
130 | * FIXME: Why doesn't a simple "./Cube/Cube/Cube" work even with a |
||
131 | * namespace resolver? |
||
132 | */ |
||
17 | PointedEar | 133 | @SuppressWarnings("nls") |
16 | PointedEar | 134 | XPathExpression expr = |
135 | xpath |
||
17 | PointedEar | 136 | .compile("./*[local-name() = 'Cube']/*[local-name() = 'Cube']"); |
137 | NodeList nodes = (NodeList) |
||
16 | PointedEar | 138 | expr.evaluate(doc.getDocumentElement(), XPathConstants.NODESET); |
17 | PointedEar | 139 | Element parentCube = (Element) nodes.item(0); |
140 | if (parentCube == null) |
||
141 | { |
||
142 | return; |
||
143 | } |
||
16 | PointedEar | 144 | |
17 | PointedEar | 145 | try |
146 | { |
||
18 | PointedEar | 147 | updated = |
148 | df.parse(parentCube.getAttribute(RatesUpdater.ATTR_TIME)); |
||
17 | PointedEar | 149 | } |
150 | catch (ParseException e) |
||
151 | { |
||
152 | Log.e(this.getClass().toString(), |
||
18 | PointedEar | 153 | "Could not parse the `time' attribute into a Date", e); //$NON-NLS-1$ |
17 | PointedEar | 154 | } |
16 | PointedEar | 155 | |
17 | PointedEar | 156 | expr = |
157 | xpath |
||
158 | .compile("./*[local-name()='Cube' and (@currency='CHF' or @currency='USD')]"); //$NON-NLS-1$ |
||
159 | nodes = |
||
160 | (NodeList) expr.evaluate(parentCube, XPathConstants.NODESET); |
||
161 | NodeList childCubes = nodes; |
||
16 | PointedEar | 162 | |
17 | PointedEar | 163 | len = childCubes.getLength(); |
16 | PointedEar | 164 | |
17 | PointedEar | 165 | HashMap<String, ConversionData> conversionRates = |
166 | this.activityContext.getConversionRates(); |
||
16 | PointedEar | 167 | for (int i = 0; i < len; ++i) |
168 | { |
||
17 | PointedEar | 169 | Element item = (Element) childCubes.item(i); |
18 | PointedEar | 170 | String currency = item.getAttribute(RatesUpdater.ATTR_CURRENCY); |
16 | PointedEar | 171 | |
17 | PointedEar | 172 | try |
173 | { |
||
174 | Double rate = |
||
18 | PointedEar | 175 | Double.parseDouble(item.getAttribute(RatesUpdater.ATTR_RATE)); |
17 | PointedEar | 176 | conversionRates |
177 | .put(currency, new ConversionData(rate, updated)); |
||
178 | } |
||
179 | catch (NumberFormatException e) |
||
180 | { |
||
181 | |||
182 | } |
||
16 | PointedEar | 183 | } |
17 | PointedEar | 184 | |
185 | this.activityContext.getDatabase().writeConversionsToDatabase(null); |
||
16 | PointedEar | 186 | } |
187 | catch (XPathExpressionException e) |
||
188 | { |
||
18 | PointedEar | 189 | Log.e(this.getClass().toString(), "Error in XPath expression", e); //$NON-NLS-1$ |
16 | PointedEar | 190 | } |
191 | } |
||
192 | catch (SAXException e) |
||
193 | { |
||
17 | PointedEar | 194 | Log.e(this.getClass().toString(), |
18 | PointedEar | 195 | "Exception while parsing external XML resource", e); //$NON-NLS-1$ |
16 | PointedEar | 196 | } |
197 | catch (IOException e) |
||
198 | { |
||
17 | PointedEar | 199 | Log.e(this.getClass().toString(), |
18 | PointedEar | 200 | "I/O exception while parsing external XML resource", e); //$NON-NLS-1$ |
16 | PointedEar | 201 | } |
202 | } |
||
203 | catch (ParserConfigurationException e) |
||
204 | { |
||
17 | PointedEar | 205 | Log.e(this.getClass().toString(), |
18 | PointedEar | 206 | "Document builder cannot be created", e); //$NON-NLS-1$ |
16 | PointedEar | 207 | } |
17 | PointedEar | 208 | |
209 | if (len > 0) |
||
210 | { |
||
211 | /* |
||
212 | * Notify the activity that we are done (causes a notification to be |
||
213 | * shown) |
||
214 | */ |
||
215 | Intent intent = new Intent(UpdateService.ACTION_UPDATE); |
||
216 | intent.putExtra(UpdateService.EXTRA_NUM_RATES, len); |
||
217 | intent.putExtra(UpdateService.EXTRA_DATE, updated); |
||
218 | this.service.sendBroadcast(intent); |
||
219 | } |
||
220 | |||
221 | textUpdating.setVisibility(View.GONE); |
||
16 | PointedEar | 222 | } |
223 | } |
||
224 | } |