/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.hadoop.hive.ql.parse.repl.load;
import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.metastore.api.Function;
import org.apache.hadoop.hive.metastore.api.Partition;
import org.apache.hadoop.hive.metastore.api.Table;
import org.apache.hadoop.hive.ql.parse.EximUtil;
import org.apache.hadoop.hive.ql.parse.ReplicationSpec;
import org.apache.hadoop.hive.ql.parse.SemanticException;
import org.apache.hadoop.hive.ql.parse.repl.dump.io.DBSerializer;
import org.apache.hadoop.hive.ql.parse.repl.dump.io.FunctionSerializer;
import org.apache.hadoop.hive.ql.parse.repl.dump.io.PartitionSerializer;
import org.apache.hadoop.hive.ql.parse.repl.dump.io.TableSerializer;
import org.apache.thrift.TBase;
import org.apache.thrift.TDeserializer;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TJSONProtocol;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import static org.apache.hadoop.hive.ql.parse.repl.dump.io.JsonWriter.Serializer.UTF_8;
public class MetadataJson {
private final JSONObject json;
private final TDeserializer deserializer;
private final String tableDesc;
public MetadataJson(String message) throws JSONException, SemanticException {
deserializer = new TDeserializer(new TJSONProtocol.Factory());
json = new JSONObject(message);
checkCompatibility();
tableDesc = jsonEntry(TableSerializer.FIELD_NAME);
}
public MetaData getMetaData() throws TException, JSONException {
return new MetaData(
database(),
table(),
partitions(),
readReplicationSpec(),
function()
);
}
private Function function() throws TException {
return deserialize(new Function(), jsonEntry(FunctionSerializer.FIELD_NAME));
}
private Database database() throws TException {
return deserialize(new Database(), jsonEntry(DBSerializer.FIELD_NAME));
}
private Table table() throws TException {
return deserialize(new Table(), tableDesc);
}
private <T extends TBase> T deserialize(T intoObject, String json) throws TException {
if (json == null) {
return null;
}
deserializer.deserialize(intoObject, json, UTF_8);
return intoObject;
}
private List<Partition> partitions() throws JSONException, TException {
if (tableDesc == null) {
return null;
}
// TODO : jackson-streaming-iterable-redo this
JSONArray jsonPartitions = new JSONArray(json.getString(PartitionSerializer.FIELD_NAME));
List<Partition> partitionsList = new ArrayList<>(jsonPartitions.length());
for (int i = 0; i < jsonPartitions.length(); ++i) {
String partDesc = jsonPartitions.getString(i);
partitionsList.add(deserialize(new Partition(), partDesc));
}
return partitionsList;
}
private ReplicationSpec readReplicationSpec() {
com.google.common.base.Function<String, String> keyFetcher =
new com.google.common.base.Function<String, String>() {
@Override
public String apply(@Nullable String s) {
return jsonEntry(s);
}
};
return new ReplicationSpec(keyFetcher);
}
private void checkCompatibility() throws SemanticException, JSONException {
String version = json.getString("version");
String fcVersion = jsonEntry("fcversion");
EximUtil.doCheckCompatibility(
EximUtil.METADATA_FORMAT_VERSION,
version,
fcVersion);
}
private String jsonEntry(String forName) {
try {
return json.getString(forName);
} catch (JSONException ignored) {
return null;
}
}
}