OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / sax / tests / saxtests / src / android / sax / SafeSaxTest.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.sax;
18
19 import android.graphics.Bitmap;
20 import android.sax.Element;
21 import android.sax.ElementListener;
22 import android.sax.EndTextElementListener;
23 import android.sax.RootElement;
24 import android.sax.StartElementListener;
25 import android.sax.TextElementListener;
26 import android.test.AndroidTestCase;
27 import android.test.suitebuilder.annotation.LargeTest;
28 import android.test.suitebuilder.annotation.SmallTest;
29 import android.text.format.Time;
30 import android.util.Log;
31 import android.util.Xml;
32 import com.android.internal.util.XmlUtils;
33 import org.xml.sax.Attributes;
34 import org.xml.sax.ContentHandler;
35 import org.xml.sax.SAXException;
36 import org.xml.sax.helpers.DefaultHandler;
37
38 import java.io.ByteArrayInputStream;
39 import java.io.ByteArrayOutputStream;
40 import java.io.IOException;
41 import java.io.InputStream;
42
43 import com.android.frameworks.saxtests.R;
44
45 public class SafeSaxTest extends AndroidTestCase {
46
47     private static final String TAG = SafeSaxTest.class.getName();
48
49     private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
50     private static final String MEDIA_NAMESPACE = "http://search.yahoo.com/mrss/";
51     private static final String YOUTUBE_NAMESPACE = "http://gdata.youtube.com/schemas/2007";
52     private static final String GDATA_NAMESPACE = "http://schemas.google.com/g/2005";
53
54     private static class ElementCounter implements ElementListener {
55         int starts = 0;
56         int ends = 0;
57
58         public void start(Attributes attributes) {
59             starts++;
60         }
61
62         public void end() {
63             ends++;
64         }
65     }
66
67     private static class TextElementCounter implements TextElementListener {
68         int starts = 0;
69         String bodies = "";
70
71         public void start(Attributes attributes) {
72             starts++;
73         }
74
75         public void end(String body) {
76             this.bodies += body;
77         }
78     }
79
80     @SmallTest
81     public void testListener() throws Exception {
82         String xml = "<feed xmlns='http://www.w3.org/2005/Atom'>\n"
83                 + "<entry>\n"
84                 + "<id>a</id>\n"
85                 + "</entry>\n"
86                 + "<entry>\n"
87                 + "<id>b</id>\n"
88                 + "</entry>\n"
89                 + "</feed>\n";
90
91         RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
92         Element entry = root.requireChild(ATOM_NAMESPACE, "entry");
93         Element id = entry.requireChild(ATOM_NAMESPACE, "id");
94
95         ElementCounter rootCounter = new ElementCounter();
96         ElementCounter entryCounter = new ElementCounter();
97         TextElementCounter idCounter = new TextElementCounter();
98
99         root.setElementListener(rootCounter);
100         entry.setElementListener(entryCounter);
101         id.setTextElementListener(idCounter);
102
103         Xml.parse(xml, root.getContentHandler());
104
105         assertEquals(1, rootCounter.starts);
106         assertEquals(1, rootCounter.ends);
107         assertEquals(2, entryCounter.starts);
108         assertEquals(2, entryCounter.ends);
109         assertEquals(2, idCounter.starts);
110         assertEquals("ab", idCounter.bodies);
111     }
112
113     @SmallTest
114     public void testMissingRequiredChild() throws Exception {
115         String xml = "<feed></feed>";
116         RootElement root = new RootElement("feed");
117         root.requireChild("entry");
118
119         try {
120             Xml.parse(xml, root.getContentHandler());
121             fail("expected exception not thrown");
122         } catch (SAXException e) {
123             // Expected.
124         }
125     }
126
127     @SmallTest
128     public void testMixedContent() throws Exception {
129         String xml = "<feed><entry></entry></feed>";
130
131         RootElement root = new RootElement("feed");
132         root.setEndTextElementListener(new EndTextElementListener() {
133             public void end(String body) {
134             }
135         });
136
137         try {
138             Xml.parse(xml, root.getContentHandler());
139             fail("expected exception not thrown");
140         } catch (SAXException e) {
141             // Expected.
142         }
143     }
144
145     @LargeTest
146     public void testPerformance() throws Exception {
147         InputStream in = mContext.getResources().openRawResource(R.raw.youtube);
148         byte[] xmlBytes;
149         try {
150             ByteArrayOutputStream out = new ByteArrayOutputStream();
151             byte[] buffer = new byte[1024];
152             int length;
153             while ((length = in.read(buffer)) != -1) {
154                 out.write(buffer, 0, length);
155             }
156             xmlBytes = out.toByteArray();
157         } finally {
158             in.close();
159         }
160
161         Log.i("***", "File size: " + (xmlBytes.length / 1024) + "k");
162
163         VideoAdapter videoAdapter = new VideoAdapter();
164         ContentHandler handler = newContentHandler(videoAdapter);
165         for (int i = 0; i < 2; i++) {
166             pureSaxTest(new ByteArrayInputStream(xmlBytes));
167             saxyModelTest(new ByteArrayInputStream(xmlBytes));
168             saxyModelTest(new ByteArrayInputStream(xmlBytes), handler);
169         }
170     }
171
172     private static void pureSaxTest(InputStream inputStream) throws IOException, SAXException {
173         long start = System.currentTimeMillis();
174         VideoAdapter videoAdapter = new VideoAdapter();
175         Xml.parse(inputStream, Xml.Encoding.UTF_8, new YouTubeContentHandler(videoAdapter));
176         long elapsed = System.currentTimeMillis() - start;
177         Log.i(TAG, "pure SAX: " + elapsed + "ms");
178     }
179
180     private static void saxyModelTest(InputStream inputStream) throws IOException, SAXException {
181         long start = System.currentTimeMillis();
182         VideoAdapter videoAdapter = new VideoAdapter();
183         Xml.parse(inputStream, Xml.Encoding.UTF_8, newContentHandler(videoAdapter));
184         long elapsed = System.currentTimeMillis() - start;
185         Log.i(TAG, "Saxy Model: " + elapsed + "ms");
186     }
187
188     private static void saxyModelTest(InputStream inputStream, ContentHandler contentHandler)
189             throws IOException, SAXException {
190         long start = System.currentTimeMillis();
191         Xml.parse(inputStream, Xml.Encoding.UTF_8, contentHandler);
192         long elapsed = System.currentTimeMillis() - start;
193         Log.i(TAG, "Saxy Model (preloaded): " + elapsed + "ms");
194     }
195
196     private static class VideoAdapter {
197         public void addVideo(YouTubeVideo video) {
198         }
199     }
200
201     private static ContentHandler newContentHandler(VideoAdapter videoAdapter) {
202         return new HandlerFactory().newContentHandler(videoAdapter);
203     }
204
205     private static class HandlerFactory {
206         YouTubeVideo video;
207
208         public ContentHandler newContentHandler(VideoAdapter videoAdapter) {
209             RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
210
211             final VideoListener videoListener = new VideoListener(videoAdapter);
212
213             Element entry = root.getChild(ATOM_NAMESPACE, "entry");
214
215             entry.setElementListener(videoListener);
216
217             entry.getChild(ATOM_NAMESPACE, "id")
218                     .setEndTextElementListener(new EndTextElementListener() {
219                         public void end(String body) {
220                             video.videoId = body;
221                         }
222                     });
223
224             entry.getChild(ATOM_NAMESPACE, "published")
225                     .setEndTextElementListener(new EndTextElementListener() {
226                         public void end(String body) {
227                             // TODO(tomtaylor): programmatically get the timezone
228                             video.dateAdded = new Time(Time.TIMEZONE_UTC);
229                             video.dateAdded.parse3339(body);
230                         }
231                     });
232
233             Element author = entry.getChild(ATOM_NAMESPACE, "author");
234             author.getChild(ATOM_NAMESPACE, "name")
235                     .setEndTextElementListener(new EndTextElementListener() {
236                         public void end(String body) {
237                             video.authorName = body;
238                         }
239                     });
240
241             Element mediaGroup = entry.getChild(MEDIA_NAMESPACE, "group");
242
243             mediaGroup.getChild(MEDIA_NAMESPACE, "thumbnail")
244                     .setStartElementListener(new StartElementListener() {
245                         public void start(Attributes attributes) {
246                             String url = attributes.getValue("", "url");
247                             if (video.thumbnailUrl == null && url.length() > 0) {
248                                 video.thumbnailUrl = url;
249                             }
250                         }
251                     });
252
253             mediaGroup.getChild(MEDIA_NAMESPACE, "content")
254                     .setStartElementListener(new StartElementListener() {
255                         public void start(Attributes attributes) {
256                             String url = attributes.getValue("", "url");
257                             if (url != null) {
258                                 video.videoUrl = url;
259                             }
260                         }
261                     });
262
263             mediaGroup.getChild(MEDIA_NAMESPACE, "player")
264                     .setStartElementListener(new StartElementListener() {
265                         public void start(Attributes attributes) {
266                             String url = attributes.getValue("", "url");
267                             if (url != null) {
268                                 video.playbackUrl = url;
269                             }
270                         }
271                     });
272
273             mediaGroup.getChild(MEDIA_NAMESPACE, "title")
274                     .setEndTextElementListener(new EndTextElementListener() {
275                         public void end(String body) {
276                             video.title = body;
277                         }
278                     });
279
280             mediaGroup.getChild(MEDIA_NAMESPACE, "category")
281                     .setEndTextElementListener(new EndTextElementListener() {
282                         public void end(String body) {
283                             video.category = body;
284                         }
285                     });
286
287             mediaGroup.getChild(MEDIA_NAMESPACE, "description")
288                     .setEndTextElementListener(new EndTextElementListener() {
289                         public void end(String body) {
290                             video.description = body;
291                         }
292                     });
293
294             mediaGroup.getChild(MEDIA_NAMESPACE, "keywords")
295                     .setEndTextElementListener(new EndTextElementListener() {
296                         public void end(String body) {
297                             video.tags = body;
298                         }
299                     });
300
301             mediaGroup.getChild(YOUTUBE_NAMESPACE, "duration")
302                     .setStartElementListener(new StartElementListener() {
303                         public void start(Attributes attributes) {
304                             String seconds = attributes.getValue("", "seconds");
305                             video.lengthInSeconds
306                                     = XmlUtils.convertValueToInt(seconds, 0);
307                         }
308                     });
309
310             mediaGroup.getChild(YOUTUBE_NAMESPACE, "statistics")
311                     .setStartElementListener(new StartElementListener() {
312                         public void start(Attributes attributes) {
313                             String viewCount = attributes.getValue("", "viewCount");
314                             video.viewCount
315                                     = XmlUtils.convertValueToInt(viewCount, 0);
316                         }
317                     });
318
319             entry.getChild(GDATA_NAMESPACE, "rating")
320                     .setStartElementListener(new StartElementListener() {
321                         public void start(Attributes attributes) {
322                             String average = attributes.getValue("", "average");
323                             video.rating = average == null
324                                     ? 0.0f : Float.parseFloat(average);
325                         }
326                     });
327
328             return root.getContentHandler();
329         }
330
331         class VideoListener implements ElementListener {
332
333             final VideoAdapter videoAdapter;
334
335             public VideoListener(VideoAdapter videoAdapter) {
336                 this.videoAdapter = videoAdapter;
337             }
338
339             public void start(Attributes attributes) {
340                 video = new YouTubeVideo();
341             }
342
343             public void end() {
344                 videoAdapter.addVideo(video);
345                 video = null;
346             }
347         }
348     }
349
350     private static class YouTubeContentHandler extends DefaultHandler {
351
352         final VideoAdapter videoAdapter;
353
354         YouTubeVideo video = null;
355         StringBuilder builder = null;
356
357         public YouTubeContentHandler(VideoAdapter videoAdapter) {
358             this.videoAdapter = videoAdapter;
359         }
360
361         @Override
362         public void startElement(String uri, String localName, String qName,
363                 Attributes attributes) throws SAXException {
364             if (uri.equals(ATOM_NAMESPACE)) {
365                 if (localName.equals("entry")) {
366                     video = new YouTubeVideo();
367                     return;
368                 }
369
370                 if (video == null) {
371                     return;
372                 }
373
374                 if (!localName.equals("id")
375                         && !localName.equals("published")
376                         && !localName.equals("name")) {
377                     return;
378                 }
379                 this.builder = new StringBuilder();
380                 return;
381
382             }
383
384             if (video == null) {
385                 return;
386             }
387
388             if (uri.equals(MEDIA_NAMESPACE)) {
389                 if (localName.equals("thumbnail")) {
390                     String url = attributes.getValue("", "url");
391                     if (video.thumbnailUrl == null && url.length() > 0) {
392                         video.thumbnailUrl = url;
393                     }
394                     return;
395                 }
396
397                 if (localName.equals("content")) {
398                     String url = attributes.getValue("", "url");
399                     if (url != null) {
400                         video.videoUrl = url;
401                     }
402                     return;
403                 }
404
405                 if (localName.equals("player")) {
406                     String url = attributes.getValue("", "url");
407                     if (url != null) {
408                         video.playbackUrl = url;
409                     }
410                     return;
411                 }
412
413                 if (localName.equals("title")
414                         || localName.equals("category")
415                         || localName.equals("description")
416                         || localName.equals("keywords")) {
417                     this.builder = new StringBuilder();
418                     return;
419                 }
420
421                 return;
422             }
423
424             if (uri.equals(YOUTUBE_NAMESPACE)) {
425                 if (localName.equals("duration")) {
426                     video.lengthInSeconds = XmlUtils.convertValueToInt(
427                             attributes.getValue("", "seconds"), 0);
428                     return;
429                 }
430
431                 if (localName.equals("statistics")) {
432                     video.viewCount = XmlUtils.convertValueToInt(
433                             attributes.getValue("", "viewCount"), 0);
434                     return;
435                 }
436
437                 return;
438             }
439
440             if (uri.equals(GDATA_NAMESPACE)) {
441                 if (localName.equals("rating")) {
442                     String average = attributes.getValue("", "average");
443                     video.rating = average == null
444                             ? 0.0f : Float.parseFloat(average);
445                 }
446             }
447         }
448
449         @Override
450         public void characters(char text[], int start, int length)
451                 throws SAXException {
452             if (builder != null) {
453                 builder.append(text, start, length);
454             }
455         }
456
457         String takeText() {
458             try {
459                 return builder.toString();
460             } finally {
461                 builder = null;
462             }
463         }
464
465         @Override
466         public void endElement(String uri, String localName, String qName)
467                 throws SAXException {
468             if (video == null) {
469                 return;
470             }
471
472             if (uri.equals(ATOM_NAMESPACE)) {
473                 if (localName.equals("published")) {
474                     // TODO(tomtaylor): programmatically get the timezone
475                     video.dateAdded = new Time(Time.TIMEZONE_UTC);
476                     video.dateAdded.parse3339(takeText());
477                     return;
478                 }
479
480                 if (localName.equals("name")) {
481                     video.authorName = takeText();
482                     return;
483                 }
484
485                 if (localName.equals("id")) {
486                     video.videoId = takeText();
487                     return;
488                 }
489
490                 if (localName.equals("entry")) {
491                     // Add the video!
492                     videoAdapter.addVideo(video);
493                     video = null;
494                     return;
495                 }
496
497                 return;
498             }
499
500             if (uri.equals(MEDIA_NAMESPACE)) {
501                 if (localName.equals("description")) {
502                     video.description = takeText();
503                     return;
504                 }
505
506                 if (localName.equals("keywords")) {
507                     video.tags = takeText();
508                     return;
509                 }
510
511                 if (localName.equals("category")) {
512                     video.category = takeText();
513                     return;
514                 }
515
516                 if (localName.equals("title")) {
517                     video.title = takeText();
518                 }
519             }
520         }
521     }
522
523     private static class YouTubeVideo {
524         public String videoId;     // the id used to lookup on YouTube
525         public String videoUrl;       // the url to play the video
526         public String playbackUrl;    // the url to share for users to play video
527         public String thumbnailUrl;   // the url of the thumbnail image
528         public String title;
529         public Bitmap bitmap;      // cached bitmap of the thumbnail
530         public int lengthInSeconds;
531         public int viewCount;      // number of times the video has been viewed
532         public float rating;       // ranges from 0.0 to 5.0
533         public Boolean triedToLoadThumbnail;
534         public String authorName;
535         public Time dateAdded;
536         public String category;
537         public String tags;
538         public String description;
539     }
540 }
541