/**
* Licensed to JumpMind Inc under one or more contributor
* license agreements. See the NOTICE file distributed
* with this work for additional information regarding
* copyright ownership. JumpMind Inc licenses this file
* to you under the GNU General Public License, version 3.0 (GPLv3)
* (the "License"); you may not use this file except in compliance
* with the License.
*
* You should have received a copy of the GNU General Public License,
* version 3.0 (GPLv3) along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* 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 org.jumpmind.symmetric.io.data.reader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.jumpmind.db.io.DatabaseXmlUtil;
import org.jumpmind.db.model.Column;
import org.jumpmind.db.model.Database;
import org.jumpmind.db.model.Table;
import org.jumpmind.db.util.BinaryEncoding;
import org.jumpmind.exception.IoException;
import org.jumpmind.symmetric.io.data.Batch;
import org.jumpmind.symmetric.io.data.CsvData;
import org.jumpmind.symmetric.io.data.CsvUtils;
import org.jumpmind.symmetric.io.data.DataContext;
import org.jumpmind.symmetric.io.data.DataEventType;
import org.jumpmind.symmetric.io.data.IDataReader;
import org.jumpmind.util.Statistics;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
public class XmlDataReader extends AbstractDataReader implements IDataReader {
protected Reader reader;
protected DataContext context;
protected Batch batch;
protected Table table;
protected String sourceNodeId;
protected int lineNumber = 0;
protected XmlPullParser parser;
protected Statistics statistics = new Statistics();
protected List<Object> next = new ArrayList<Object>();
public XmlDataReader(InputStream is) {
this(toReader(is));
}
public XmlDataReader(Reader reader) {
this.reader = reader;
}
public void open(DataContext context) {
try {
this.lineNumber = 0;
this.context = context;
this.parser = XmlPullParserFactory.newInstance().newPullParser();
this.parser.setInput(reader);
readNext();
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
}
}
protected void readNext() {
try {
Map<String, String> rowData = new LinkedHashMap<String, String>();
String columnName = null;
CsvData data = null;
Table table = null;
String catalog = null;
String schema = null;
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.TEXT:
if (columnName != null) {
rowData.put(columnName, parser.getText());
columnName = null;
}
break;
case XmlPullParser.START_TAG:
String name = parser.getName();
if ("row".equalsIgnoreCase(name)) {
data = new CsvData();
if (table != null) {
table.removeAllColumns();
}
data.setDataEventType(DataEventType.INSERT);
} else if ("field".equalsIgnoreCase(name)) {
boolean nullValue = false;
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if ("name".equalsIgnoreCase(attributeName)) {
columnName = attributeValue;
} else if ("xsi:nil".equalsIgnoreCase(attributeName)) {
nullValue = true;
}
}
if (nullValue) {
rowData.put(columnName, null);
columnName = null;
}
} else if ("table_data".equalsIgnoreCase(name)) {
Batch batch = new Batch();
batch.setBinaryEncoding(BinaryEncoding.BASE64);
next.add(batch);
table = new Table();
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if ("name".equalsIgnoreCase(attributeName)) {
table.setName(attributeValue);
}
}
next.add(table);
} else if ("table".equalsIgnoreCase(name)) {
Batch batch = new Batch();
batch.setBinaryEncoding(BinaryEncoding.BASE64);
next.add(batch);
table = DatabaseXmlUtil.nextTable(parser);
next.add(table);
Database db = new Database();
db.setName("dbimport");
db.setCatalog(catalog);
db.setSchema(schema);
db.addTable(table);
String xml = DatabaseXmlUtil.toXml(db);
data = new CsvData(DataEventType.CREATE);
data.putCsvData(CsvData.ROW_DATA, CsvUtils.escapeCsvData(xml));
next.add(data);
} else if ("database".equalsIgnoreCase(name)) {
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if ("catalog".equalsIgnoreCase(attributeName)) {
catalog = attributeValue;
} else if ("schema".equalsIgnoreCase(attributeName)) {
schema = attributeValue;
}
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if ("row".equalsIgnoreCase(name)) {
String[] columnNames = rowData.keySet().toArray(
new String[rowData.keySet().size()]);
for (String colName : columnNames) {
table.addColumn(new Column(colName));
}
String[] columnValues = rowData.values().toArray(
new String[rowData.values().size()]);
data.putParsedData(CsvData.ROW_DATA, columnValues);
if (this.table == null || !this.table.equals(table)) {
next.add(table);
}
next.add(data);
rowData = new LinkedHashMap<String, String>();
} else if ("table_data".equalsIgnoreCase(name)) {
if (batch != null) {
batch.setComplete(true);
}
} else if ("field".equalsIgnoreCase(name)) {
columnName = null;
}
break;
}
eventType = parser.next();
}
} catch (IOException ex) {
throw new IoException(ex);
} catch (XmlPullParserException ex) {
throw new RuntimeException(ex);
}
}
public Batch nextBatch() {
do {
readNext();
if (next.size() > 0) {
Object o = next.remove(0);
if (o instanceof Batch) {
batch = (Batch) o;
return batch;
}
}
} while (next.size() > 0);
return null;
}
public Table nextTable() {
this.table = null;
do {
readNext();
if (next.size() > 0) {
Object o = next.remove(0);
if (o instanceof Table) {
this.table = (Table) o;
break;
}
}
} while (next.size() > 0);
if (this.table == null && batch != null) {
batch.setComplete(true);
}
return this.table;
}
public CsvData nextData() {
readNext();
if (next.size() > 0 && next.get(0) instanceof CsvData) {
return (CsvData) next.remove(0);
}
return null;
}
public void close() {
IOUtils.closeQuietly(reader);
}
public Map<Batch, Statistics> getStatistics() {
Map<Batch, Statistics> map = new HashMap<Batch, Statistics>(1);
map.put(batch, statistics);
return map;
}
}