blob: bcc839dc27be0fed013940960fb7dc9d3f260e63 [file] [log] [blame]
/*
* 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.knox.gateway.shell.table;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* A custom @JsonDeserializer in order to be able to deserialize a previously
* serialized {@link KnoxShellTable}. It is required because
* <ul>
* <li>Jackson is not capable of constructing instance of `java.lang.Comparable`
* (which we have in the table cells)</li>
* <li><code>callHistory</code> deserialization requires special handling
* </ul>
*
*/
@SuppressWarnings("serial")
public class KnoxShellTableRowDeserializer extends StdDeserializer<KnoxShellTable> {
KnoxShellTableRowDeserializer() {
this(KnoxShellTable.class);
}
protected KnoxShellTableRowDeserializer(Class<?> vc) {
super(vc);
}
@Override
public KnoxShellTable deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
final TreeNode jsonContent = parser.readValueAsTree();
if (jsonContent.get("callHistoryList") != null) {
return parseJsonWithCallHistory(jsonContent);
} else {
return parseJsonWithData(jsonContent);
}
}
private KnoxShellTable parseJsonWithCallHistory(TreeNode jsonContent) throws IOException {
final List<KnoxShellTableCall> calls = parseCallHistoryListJSONNode(jsonContent.get("callHistoryList"));
long tempId = KnoxShellTable.getUniqueTableId();
KnoxShellTableCallHistory.getInstance().saveCalls(tempId, calls);
final KnoxShellTable table = KnoxShellTableCallHistory.getInstance().replay(tempId, calls.size());
KnoxShellTableCallHistory.getInstance().removeCallsById(tempId);
return table;
}
private List<KnoxShellTableCall> parseCallHistoryListJSONNode(TreeNode callHistoryNode) throws IOException {
final List<KnoxShellTableCall> callHistoryList = new LinkedList<KnoxShellTableCall>();
TreeNode callNode;
Map<Object, Class<?>> params;
String invokerClass, method;
Boolean builderMethod;
for (int i = 0; i < callHistoryNode.size(); i++) {
callNode = callHistoryNode.get(i);
invokerClass = trimJSONQuotes(callNode.get("invokerClass").toString());
method = trimJSONQuotes(callNode.get("method").toString());
builderMethod = Boolean.valueOf(trimJSONQuotes(callNode.get("builderMethod").toString()));
params = fetchParameterMap(callNode.get("params"));
callHistoryList.add(new KnoxShellTableCall(invokerClass, method, builderMethod, params));
}
return callHistoryList;
}
private Map<Object, Class<?>> fetchParameterMap(TreeNode paramsNode) throws IOException {
try {
final Map<Object, Class<?>> parameterMap = new HashMap<>();
final Iterator<String> paramsFieldNamesIterator = ((ObjectNode) paramsNode).fieldNames();
String parameterValueAsString;
Class<?> parameterType;
while (paramsFieldNamesIterator.hasNext()) {
parameterValueAsString = trimJSONQuotes(paramsFieldNamesIterator.next());
parameterType = Class.forName(trimJSONQuotes(paramsNode.get(parameterValueAsString).toString()));
parameterMap.put(cast(parameterValueAsString, parameterType), parameterType);
}
return parameterMap;
} catch (Exception e) {
throw new IOException("Error while fetching parameters " + paramsNode, e);
}
}
// This may be done in a different way or using a library; I did not find any (I
// did not do a deep search though)
private Object cast(String valueAsString, Class<?> type) throws ParseException {
if (String.class == type) {
return valueAsString;
} else if (Byte.class == type) {
return Byte.valueOf(valueAsString);
} else if (Short.class == type) {
return Short.valueOf(valueAsString);
} else if (Integer.class == type) {
return Integer.valueOf(valueAsString);
} else if (Long.class == type) {
return Long.valueOf(valueAsString);
} else if (Float.class == type) {
return Float.valueOf(valueAsString);
} else if (Double.class == type) {
return Double.valueOf(valueAsString);
} else if (Boolean.class == type) {
return Boolean.valueOf(valueAsString);
} else if (Date.class == type) {
return KnoxShellTableJSONSerializer.JSON_DATE_FORMAT.parse(valueAsString);
}
return type.cast(valueAsString); // may throw ClassCastException
}
private KnoxShellTable parseJsonWithData(final TreeNode jsonContent) {
final KnoxShellTable table = new KnoxShellTable();
if (jsonContent.get("title").size() != 0) {
table.title(trimJSONQuotes(jsonContent.get("title").toString()));
}
final TreeNode headers = jsonContent.get("headers");
for (int i = 0; i < headers.size(); i++) {
table.header(trimJSONQuotes(headers.get(i).toString()));
}
final TreeNode rows = jsonContent.get("rows");
for (int i = 0; i < rows.size(); i++) {
TreeNode row = rows.get(i);
table.row();
for (int j = 0; j < row.size(); j++) {
table.value(trimJSONQuotes(row.get(j).toString()));
}
}
return table;
}
/*
* When serializing an object as JSON all elements within the table receive a
* surrounding quote pair (e.g. the cell contains myValue -> the JSON serialized
* string will be "myValue")
*/
private String trimJSONQuotes(String toBeTrimmed) {
return toBeTrimmed.replaceAll("\"", "");
}
}