/**
* DataCleaner (community edition)
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.metamodel.datahub.utils;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.metamodel.schema.ColumnTypeImpl;
import org.apache.metamodel.schema.MutableColumn;
import org.apache.metamodel.schema.MutableTable;
import org.datacleaner.metamodel.datahub.DataHubSchema;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class JsonSchemasResponseParser {
private enum DatastoreObject {
DATASTORE {
@Override
public DatastoreObject previous() {
return null; // see below for options for this line
}
}, SCHEMA, TABLE, COLUMN {
@Override
public DatastoreObject next() {
return null; // see below for options for this line
}
};
public DatastoreObject next() {
// No bounds checking required here, because the last instance
// overrides
return values()[ordinal() + 1];
}
public DatastoreObject previous() {
// No bounds checking required here, because the first instance
// overrides
return values()[ordinal() - 1];
}
}
private static final Set<String> datastoreTypes = new HashSet<>(Arrays.asList(
new String[] { "GoldenRecordDatastore", "SourceRecordSourceFormatDatastore",
"SourceRecordGoldenFormatDatastore" }));
private DatastoreObject _currentObject;
private String _currentFieldname;
private DataHubSchema _currentSchema;
private MutableTable _currentTable;
private MutableColumn _currentColumn;
private DataHubSchema _resultSchema;
private String _currentDataStoreName;
private List<String> _dataStoreNames = new ArrayList<>();
public DataHubSchema parseJsonSchema(final InputStream is) throws JsonParseException, IOException {
_currentObject = DatastoreObject.DATASTORE;
_currentFieldname = "";
final JsonFactory factory = new JsonFactory();
final JsonParser parser = factory.createParser(is);
JsonToken token = parser.nextToken();
while (token != null) {
switch (parser.getCurrentToken()) {
case START_ARRAY:
_currentObject = _currentObject.next();
break;
case END_ARRAY:
_currentObject = _currentObject.previous();
break;
case START_OBJECT:
createNewObject();
break;
case END_OBJECT:
addObjectToSchema();
break;
case FIELD_NAME:
_currentFieldname = parser.getText();
break;
case VALUE_STRING:
handleValue(_currentFieldname, parser.getText());
break;
case VALUE_FALSE:
handleBooleanValue(_currentFieldname, false);
break;
case VALUE_TRUE:
handleBooleanValue(_currentFieldname, true);
break;
case VALUE_NUMBER_INT:
handleIntegerValue(_currentFieldname, parser.getIntValue());
break;
default:
break;
}
token = parser.nextToken();
}
return _resultSchema;
}
private void addObjectToSchema() {
switch (_currentObject) {
case SCHEMA:
if (!"INFORMATION_SCHEMA".equals(_currentSchema.getName())) {
_resultSchema = _currentSchema;
}
break;
case TABLE:
_currentTable.setSchema(_currentSchema);
_currentSchema.addTable(_currentTable);
break;
case COLUMN:
_currentColumn.setTable(_currentTable);
_currentTable.addColumn(_currentColumn);
break;
default:
}
}
private void createNewObject() {
switch (_currentObject) {
case SCHEMA:
_currentSchema = new DataHubSchema();
// TODO: Is this on purpose?
// fallthru
case TABLE:
_currentTable = new MutableTable();
break;
case COLUMN:
_currentColumn = new MutableColumn();
break;
default:
}
}
private void handleValue(final String fieldName, final String fieldValue) {
switch (_currentObject) {
case SCHEMA:
handleSchemaField(fieldName, fieldValue);
break;
case TABLE:
handleTableField(fieldName, fieldValue);
break;
case COLUMN:
handleColumnField(fieldName, fieldValue);
break;
default:
}
}
private void handleBooleanValue(final String fieldName, final boolean fieldValue) {
switch (_currentObject) {
case COLUMN:
handleBooleanColumnField(fieldName, fieldValue);
break;
default:
}
}
private void handleBooleanColumnField(final String fieldName, final boolean fieldValue) {
if (fieldName.equals("primaryKey")) {
_currentColumn.setPrimaryKey(fieldValue);
} else if (fieldName.equals("indexed")) {
_currentColumn.setIndexed(fieldValue);
} else if (fieldName.equals("nullable")) {
_currentColumn.setNullable(fieldValue);
} else {
// skip unknown column fields
}
}
private void handleIntegerValue(final String fieldName, final int fieldValue) {
if (fieldName.equals("number")) {
_currentColumn.setColumnNumber(fieldValue);
}
}
private void handleColumnField(final String fieldName, final String fieldValue) {
if (fieldName.equals("name")) {
_currentColumn.setName(fieldValue);
} else if (fieldName.equals("quote")) {
_currentColumn.setQuote(fieldValue);
} else if (fieldName.equals("remarks")) {
_currentColumn.setRemarks(fieldValue);
} else if (fieldName.equals("type")) {
_currentColumn.setType(ColumnTypeImpl.valueOf(fieldValue));
} else if (fieldName.equals("nativeType")) {
_currentColumn.setNativeType(fieldValue);
} else if (fieldName.equals("size")) {
_currentColumn.setColumnSize(new Integer(fieldValue));
} else {
// skip unknown column fields
}
}
private void handleTableField(final String fieldName, final String fieldValue) {
if (fieldName.equals("name")) {
_currentTable.setName(fieldValue);
}
}
private void handleSchemaField(final String fieldName, final String fieldValue) {
if (fieldName.equals("name")) {
_currentSchema.setName(fieldValue);
}
}
private void handleDataStoreValue(final String value) {
if (_currentFieldname.equals("name")) {
_currentDataStoreName = value;
} else if (_currentFieldname.equals("type") && datastoreTypes.contains(value)) {
_dataStoreNames.add(_currentDataStoreName);
}
}
public List<String> parseDataStoreArray(final InputStream inputStream) throws IOException {
final JsonFactory factory = new JsonFactory();
final JsonParser parser = factory.createParser(inputStream);
JsonToken token = parser.nextToken();
while (token != null) {
switch (parser.getCurrentToken()) {
case FIELD_NAME:
_currentFieldname = parser.getText();
break;
case VALUE_STRING:
handleDataStoreValue(parser.getText());
break;
default:
break;
}
token = parser.nextToken();
}
return _dataStoreNames;
}
}