/**
* 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.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.jumpmind.db.model.Column;
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.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 SymXmlDataReader extends AbstractDataReader implements IDataReader {
protected Reader reader;
protected DataContext context;
protected Batch batch;
protected Table table;
protected CsvData data;
protected String sourceNodeId;
protected int lineNumber = 0;
protected XmlPullParser parser;
protected Statistics statistics = new Statistics();
protected Object next = null;
public SymXmlDataReader(InputStream is) {
this(toReader(is));
}
public SymXmlDataReader(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);
this.next = readNext();
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
}
}
protected Object readNext() {
try {
Map<String, String> rowData = new LinkedHashMap<String, String>();
String columnName = null;
Table lastTable = this.table;
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)) {
table = new Table();
data = new CsvData();
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if (attributeName.equalsIgnoreCase("entity")) {
table.setName(attributeValue);
} else if (attributeName.equalsIgnoreCase("catalog")) {
table.setCatalog(attributeValue);
} else if (attributeName.equalsIgnoreCase("schema")) {
table.setSchema(attributeValue);
} else if (attributeName.equalsIgnoreCase("dml")) {
if (attributeValue.equals("I")) {
data.setDataEventType(DataEventType.INSERT);
} else if (attributeValue.equals("U")) {
data.setDataEventType(DataEventType.UPDATE);
} else if (attributeValue.equals("D")) {
data.setDataEventType(DataEventType.DELETE);
} else if (attributeValue.equals("C")) {
data.setDataEventType(DataEventType.CREATE);
} else if (attributeValue.equals("S")) {
data.setDataEventType(DataEventType.SQL);
} else if (attributeValue.equals("B")) {
data.setDataEventType(DataEventType.BSH);
} else if (attributeValue.equals("R")) {
data.setDataEventType(DataEventType.RELOAD);
}
}
}
} else if ("data".equalsIgnoreCase(name)) {
boolean nullValue = false;
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if ("key".equalsIgnoreCase(attributeName)) {
columnName = attributeValue;
} else if ("xsi:nil".equalsIgnoreCase(attributeName)) {
nullValue = true;
}
}
if (nullValue) {
rowData.put(columnName, null);
columnName = null;
}
} else if ("batch".equalsIgnoreCase(name)) {
batch = new Batch();
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
String attributeValue = parser.getAttributeValue(i);
if ("binary".equalsIgnoreCase(attributeName)) {
batch.setBinaryEncoding(BinaryEncoding.valueOf(attributeValue));
} else if ("nodeid".equalsIgnoreCase(attributeName)) {
batch.setSourceNodeId(attributeValue);
}
}
return batch;
}
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);
rowData = new LinkedHashMap<String, String>();
if (lastTable == null || !lastTable.equals(table)) {
return table;
} else {
return data;
}
} else if ("data".equalsIgnoreCase(name)) {
columnName = null;
}
break;
}
eventType = parser.next();
}
return null;
} catch (IOException ex) {
throw new IoException(ex);
} catch (XmlPullParserException ex) {
throw new RuntimeException(ex);
}
}
public Batch nextBatch() {
if (next instanceof Batch) {
this.batch = (Batch) next;
next = null;
return batch;
} else {
next = readNext();
if (next instanceof Batch) {
this.batch = (Batch) next;
next = null;
return batch;
}
}
return null;
}
public Table nextTable() {
if (next instanceof Table) {
this.table = (Table) next;
next = data;
} else {
next = readNext();
if (next instanceof Table) {
this.table = (Table) next;
next = data;
} else {
this.table = null;
}
}
if (this.table == null) {
batch.setComplete(true);
}
return this.table;
}
public CsvData nextData() {
if (next instanceof CsvData) {
CsvData data = (CsvData) next;
next = null;
return data;
} else {
next = readNext();
if (next instanceof CsvData) {
CsvData data = (CsvData) next;
next = null;
return data;
}
}
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;
}
}