1 /*
2  * Copyright (C) 2008 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.content;
18 
19 import android.net.Uri;
20 import android.util.Xml;
21 
22 import org.xml.sax.Attributes;
23 import org.xml.sax.Locator;
24 import org.xml.sax.SAXException;
25 
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.Stack;
29 
30 /**
31  * Inserts default data from InputStream, should be in XML format.
32  * If the provider syncs data to the server, the imported data will be synced to the server.
33  * <p>Samples:</p>
34  * <br/>
35  *  Insert one row:
36  * <pre>
37  * &lt;row uri="content://contacts/people">
38  *  &lt;Col column = "name" value = "foo feebe "/>
39  *  &lt;Col column = "addr" value = "Tx"/>
40  * &lt;/row></pre>
41  * <br/>
42  * Delete, it must be in order of uri, select, and arg:
43  * <pre>
44  * &lt;del uri="content://contacts/people" select="name=? and addr=?"
45  *  arg1 = "foo feebe" arg2 ="Tx"/></pre>
46  * <br/>
47  *  Use first row's uri to insert into another table,
48  *  content://contacts/people/1/phones:
49  * <pre>
50  * &lt;row uri="content://contacts/people">
51  *  &lt;col column = "name" value = "foo feebe"/>
52  *  &lt;col column = "addr" value = "Tx"/>
53  *  &lt;row postfix="phones">
54  *    &lt;col column="number" value="512-514-6535"/>
55  *  &lt;/row>
56  *  &lt;row postfix="phones">
57  *    &lt;col column="cell" value="512-514-6535"/>
58  *  &lt;/row>
59  * &lt;/row></pre>
60  * <br/>
61  *  Insert multiple rows in to same table and same attributes:
62  * <pre>
63  * &lt;row uri="content://contacts/people" >
64  *  &lt;row>
65  *   &lt;col column= "name" value = "foo feebe"/>
66  *   &lt;col column= "addr" value = "Tx"/>
67  *  &lt;/row>
68  *  &lt;row>
69  *  &lt;/row>
70  * &lt;/row></pre>
71  *
72  * @hide
73  */
74 public class DefaultDataHandler implements ContentInsertHandler {
75     private final static String ROW = "row";
76     private final static String COL = "col";
77     private final static String URI_STR = "uri";
78     private final static String POSTFIX = "postfix";
79     private final static String DEL = "del";
80     private final static String SELECT = "select";
81     private final static String ARG = "arg";
82 
83     private Stack<Uri> mUris = new Stack<Uri>();
84     private ContentValues mValues;
85     private ContentResolver mContentResolver;
86 
insert(ContentResolver contentResolver, InputStream in)87     public void insert(ContentResolver contentResolver, InputStream in)
88             throws IOException, SAXException {
89         mContentResolver = contentResolver;
90         Xml.parse(in, Xml.Encoding.UTF_8, this);
91     }
92 
insert(ContentResolver contentResolver, String in)93     public void insert(ContentResolver contentResolver, String in)
94         throws SAXException {
95         mContentResolver = contentResolver;
96         Xml.parse(in, this);
97     }
98 
parseRow(Attributes atts)99     private void parseRow(Attributes atts) throws SAXException {
100         String uriStr = atts.getValue(URI_STR);
101         Uri uri;
102         if (uriStr != null) {
103             // case 1
104             uri = Uri.parse(uriStr);
105             if (uri == null) {
106                 throw new SAXException("attribute " +
107                         atts.getValue(URI_STR) + " parsing failure");
108             }
109 
110         } else if (mUris.size() > 0){
111             // case 2
112             String postfix = atts.getValue(POSTFIX);
113             if (postfix != null) {
114                 uri = Uri.withAppendedPath(mUris.lastElement(),
115                         postfix);
116             } else {
117                 uri = mUris.lastElement();
118             }
119         } else {
120             throw new SAXException("attribute parsing failure");
121         }
122 
123         mUris.push(uri);
124 
125     }
126 
insertRow()127     private Uri insertRow() {
128         Uri u = mContentResolver.insert(mUris.lastElement(), mValues);
129         mValues = null;
130         return u;
131     }
132 
startElement(String uri, String localName, String name, Attributes atts)133     public void startElement(String uri, String localName, String name,
134             Attributes atts) throws SAXException {
135         if (ROW.equals(localName)) {
136             if (mValues != null) {
137                 // case 2, <Col> before <Row> insert last uri
138                 if (mUris.empty()) {
139                     throw new SAXException("uri is empty");
140                 }
141                 Uri nextUri = insertRow();
142                 if (nextUri == null) {
143                     throw new SAXException("insert to uri " +
144                             mUris.lastElement().toString() + " failure");
145                 } else {
146                     // make sure the stack lastElement save uri for more than one row
147                     mUris.pop();
148                     mUris.push(nextUri);
149                     parseRow(atts);
150                 }
151             } else {
152                 int attrLen = atts.getLength();
153                 if (attrLen == 0) {
154                     // case 3, share same uri as last level
155                     mUris.push(mUris.lastElement());
156                 } else {
157                     parseRow(atts);
158                 }
159             }
160         } else if (COL.equals(localName)) {
161             int attrLen = atts.getLength();
162             if (attrLen != 2) {
163                 throw new SAXException("illegal attributes number " + attrLen);
164             }
165             String key = atts.getValue(0);
166             String value = atts.getValue(1);
167             if (key != null && key.length() > 0 && value != null && value.length() > 0) {
168                 if (mValues == null) {
169                     mValues = new ContentValues();
170                 }
171                 mValues.put(key, value);
172             } else {
173                 throw new SAXException("illegal attributes value");
174             }
175         } else if (DEL.equals(localName)){
176             Uri u = Uri.parse(atts.getValue(URI_STR));
177             if (u == null) {
178                 throw new SAXException("attribute " +
179                         atts.getValue(URI_STR) + " parsing failure");
180             }
181             int attrLen = atts.getLength() - 2;
182             if (attrLen > 0) {
183                 String[] selectionArgs = new String[attrLen];
184                 for (int i = 0; i < attrLen; i++) {
185                     selectionArgs[i] = atts.getValue(i+2);
186                 }
187                 mContentResolver.delete(u, atts.getValue(1), selectionArgs);
188             } else if (attrLen == 0){
189                 mContentResolver.delete(u, atts.getValue(1), null);
190             } else {
191                 mContentResolver.delete(u, null, null);
192             }
193 
194         } else {
195             throw new SAXException("unknown element: " + localName);
196         }
197     }
198 
endElement(String uri, String localName, String name)199     public void endElement(String uri, String localName, String name)
200             throws SAXException {
201         if (ROW.equals(localName)) {
202             if (mUris.empty()) {
203                 throw new SAXException("uri mismatch");
204             }
205             if (mValues != null) {
206                 insertRow();
207             }
208             mUris.pop();
209         }
210     }
211 
212 
characters(char[] ch, int start, int length)213     public void characters(char[] ch, int start, int length)
214             throws SAXException {
215         // TODO Auto-generated method stub
216 
217     }
218 
endDocument()219     public void endDocument() throws SAXException {
220         // TODO Auto-generated method stub
221 
222     }
223 
endPrefixMapping(String prefix)224     public void endPrefixMapping(String prefix) throws SAXException {
225         // TODO Auto-generated method stub
226 
227     }
228 
ignorableWhitespace(char[] ch, int start, int length)229     public void ignorableWhitespace(char[] ch, int start, int length)
230             throws SAXException {
231         // TODO Auto-generated method stub
232 
233     }
234 
processingInstruction(String target, String data)235     public void processingInstruction(String target, String data)
236             throws SAXException {
237         // TODO Auto-generated method stub
238 
239     }
240 
setDocumentLocator(Locator locator)241     public void setDocumentLocator(Locator locator) {
242         // TODO Auto-generated method stub
243 
244     }
245 
skippedEntity(String name)246     public void skippedEntity(String name) throws SAXException {
247         // TODO Auto-generated method stub
248 
249     }
250 
startDocument()251     public void startDocument() throws SAXException {
252         // TODO Auto-generated method stub
253 
254     }
255 
startPrefixMapping(String prefix, String uri)256     public void startPrefixMapping(String prefix, String uri)
257             throws SAXException {
258         // TODO Auto-generated method stub
259 
260     }
261 
262 }
263