/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content;

import android.net.Uri;
import android.util.Xml;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;

Inserts default data from InputStream, should be in XML format. If the provider syncs data to the server, the imported data will be synced to the server.

Samples:


Insert one row:
<row uri="content://contacts/people">
 <Col column = "name" value = "foo feebe "/>
 <Col column = "addr" value = "Tx"/>
</row>

Delete, it must be in order of uri, select, and arg:
<del uri="content://contacts/people" select="name=? and addr=?" 
 arg1 = "foo feebe" arg2 ="Tx"/>

Use first row's uri to insert into another table, content://contacts/people/1/phones:
<row uri="content://contacts/people">
 <col column = "name" value = "foo feebe"/>
 <col column = "addr" value = "Tx"/>
 <row postfix="phones">
   <col column="number" value="512-514-6535"/>
 </row>
 <row postfix="phones">
   <col column="cell" value="512-514-6535"/>
 </row>  
</row>

Insert multiple rows in to same table and same attributes:
<row uri="content://contacts/people" >
 <row>
  <col column= "name" value = "foo feebe"/>
  <col column= "addr" value = "Tx"/>
 </row>
 <row>
 </row>
</row>
@hide
/** * Inserts default data from InputStream, should be in XML format. * If the provider syncs data to the server, the imported data will be synced to the server. * <p>Samples:</p> * <br/> * Insert one row: * <pre> * &lt;row uri="content://contacts/people"> * &lt;Col column = "name" value = "foo feebe "/> * &lt;Col column = "addr" value = "Tx"/> * &lt;/row></pre> * <br/> * Delete, it must be in order of uri, select, and arg: * <pre> * &lt;del uri="content://contacts/people" select="name=? and addr=?" * arg1 = "foo feebe" arg2 ="Tx"/></pre> * <br/> * Use first row's uri to insert into another table, * content://contacts/people/1/phones: * <pre> * &lt;row uri="content://contacts/people"> * &lt;col column = "name" value = "foo feebe"/> * &lt;col column = "addr" value = "Tx"/> * &lt;row postfix="phones"> * &lt;col column="number" value="512-514-6535"/> * &lt;/row> * &lt;row postfix="phones"> * &lt;col column="cell" value="512-514-6535"/> * &lt;/row> * &lt;/row></pre> * <br/> * Insert multiple rows in to same table and same attributes: * <pre> * &lt;row uri="content://contacts/people" > * &lt;row> * &lt;col column= "name" value = "foo feebe"/> * &lt;col column= "addr" value = "Tx"/> * &lt;/row> * &lt;row> * &lt;/row> * &lt;/row></pre> * * @hide */
public class DefaultDataHandler implements ContentInsertHandler { private final static String ROW = "row"; private final static String COL = "col"; private final static String URI_STR = "uri"; private final static String POSTFIX = "postfix"; private final static String DEL = "del"; private final static String SELECT = "select"; private final static String ARG = "arg"; private Stack<Uri> mUris = new Stack<Uri>(); private ContentValues mValues; private ContentResolver mContentResolver; public void insert(ContentResolver contentResolver, InputStream in) throws IOException, SAXException { mContentResolver = contentResolver; Xml.parse(in, Xml.Encoding.UTF_8, this); } public void insert(ContentResolver contentResolver, String in) throws SAXException { mContentResolver = contentResolver; Xml.parse(in, this); } private void parseRow(Attributes atts) throws SAXException { String uriStr = atts.getValue(URI_STR); Uri uri; if (uriStr != null) { // case 1 uri = Uri.parse(uriStr); if (uri == null) { throw new SAXException("attribute " + atts.getValue(URI_STR) + " parsing failure"); } } else if (mUris.size() > 0){ // case 2 String postfix = atts.getValue(POSTFIX); if (postfix != null) { uri = Uri.withAppendedPath(mUris.lastElement(), postfix); } else { uri = mUris.lastElement(); } } else { throw new SAXException("attribute parsing failure"); } mUris.push(uri); } private Uri insertRow() { Uri u = mContentResolver.insert(mUris.lastElement(), mValues); mValues = null; return u; } public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException { if (ROW.equals(localName)) { if (mValues != null) { // case 2, <Col> before <Row> insert last uri if (mUris.empty()) { throw new SAXException("uri is empty"); } Uri nextUri = insertRow(); if (nextUri == null) { throw new SAXException("insert to uri " + mUris.lastElement().toString() + " failure"); } else { // make sure the stack lastElement save uri for more than one row mUris.pop(); mUris.push(nextUri); parseRow(atts); } } else { int attrLen = atts.getLength(); if (attrLen == 0) { // case 3, share same uri as last level mUris.push(mUris.lastElement()); } else { parseRow(atts); } } } else if (COL.equals(localName)) { int attrLen = atts.getLength(); if (attrLen != 2) { throw new SAXException("illegal attributes number " + attrLen); } String key = atts.getValue(0); String value = atts.getValue(1); if (key != null && key.length() > 0 && value != null && value.length() > 0) { if (mValues == null) { mValues = new ContentValues(); } mValues.put(key, value); } else { throw new SAXException("illegal attributes value"); } } else if (DEL.equals(localName)){ Uri u = Uri.parse(atts.getValue(URI_STR)); if (u == null) { throw new SAXException("attribute " + atts.getValue(URI_STR) + " parsing failure"); } int attrLen = atts.getLength() - 2; if (attrLen > 0) { String[] selectionArgs = new String[attrLen]; for (int i = 0; i < attrLen; i++) { selectionArgs[i] = atts.getValue(i+2); } mContentResolver.delete(u, atts.getValue(1), selectionArgs); } else if (attrLen == 0){ mContentResolver.delete(u, atts.getValue(1), null); } else { mContentResolver.delete(u, null, null); } } else { throw new SAXException("unknown element: " + localName); } } public void endElement(String uri, String localName, String name) throws SAXException { if (ROW.equals(localName)) { if (mUris.empty()) { throw new SAXException("uri mismatch"); } if (mValues != null) { insertRow(); } mUris.pop(); } } public void characters(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub } public void endDocument() throws SAXException { // TODO Auto-generated method stub } public void endPrefixMapping(String prefix) throws SAXException { // TODO Auto-generated method stub } public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub } public void processingInstruction(String target, String data) throws SAXException { // TODO Auto-generated method stub } public void setDocumentLocator(Locator locator) { // TODO Auto-generated method stub } public void skippedEntity(String name) throws SAXException { // TODO Auto-generated method stub } public void startDocument() throws SAXException { // TODO Auto-generated method stub } public void startPrefixMapping(String prefix, String uri) throws SAXException { // TODO Auto-generated method stub } }