blob: 3782a9001f3ad7b8fe38b5cda7de7aa576be6d8e [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2010 Sony Ericsson/ST Ericsson and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sony Ericsson/ST Ericsson - initial API and implementation
* Tasktop Technologies - improvements
* Jan Lohre (SAP) - improvements
*********************************************************************/
package org.eclipse.mylyn.internal.gerrit.core.client;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jgit.diff.Edit;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.reviewdb.ApprovalCategory;
import com.google.gerrit.reviewdb.ApprovalCategory.Id;
import com.google.gerrit.reviewdb.AuthType;
import com.google.gerrit.reviewdb.PatchSetApproval;
import com.google.gerrit.reviewdb.Project;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.google.gwtjsonrpc.server.JsonServlet;
/**
* @author Steffen Pingel
*/
public class JSonSupport {
/**
* Parses a Json response.
*/
private class JSonResponseDeserializer implements JsonDeserializer<JSonResponse> {
public JSonResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject object = json.getAsJsonObject();
JSonResponse response = new JSonResponse();
response.jsonrpc = object.get("jsonrpc").getAsString(); //$NON-NLS-1$
response.id = object.get("id").getAsInt(); //$NON-NLS-1$
response.result = object.get("result"); //$NON-NLS-1$
response.error = object.get("error"); //$NON-NLS-1$
return response;
}
}
static class JSonError {
int code;
String message;
}
static class JsonRequest {
int id;
final String jsonrpc = "2.0"; //$NON-NLS-1$
String method;
final List<Object> params = new ArrayList<Object>();
String xsrfKey;
}
static class JSonResponse {
JsonElement error;
int id;
String jsonrpc;
JsonElement result;
}
private Gson gson;
public JSonSupport() {
TypeToken<Map<Id, PatchSetApproval>> approvalMapType = new TypeToken<Map<ApprovalCategory.Id, PatchSetApproval>>() {
};
ExclusionStrategy exclustionStrategy = new ExclusionStrategy() {
public boolean shouldSkipField(FieldAttributes f) {
// commentLinks requires instantiation of com.google.gwtexpui.safehtml.client.RegexFindReplace which is not on classpath
if (f.getDeclaredClass() == List.class
&& f.getName().equals("commentLinks") && f.getDeclaringClass() == GerritConfig.class) { //$NON-NLS-1$
return true;
}
if (f.getDeclaredClass() == Map.class && f.getName().equals("given")) { //$NON-NLS-1$
//return true;
}
// GSon 2.1 fails to deserialize the SubmitType enum
if (f.getDeclaringClass() == Project.class && f.getName().equals("submitType")) { //$NON-NLS-1$
return true;
}
return false;
}
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
};
gson = JsonServlet.defaultGsonBuilder()
.registerTypeAdapter(JSonResponse.class, new JSonResponseDeserializer())
.registerTypeAdapter(Edit.class, new JsonDeserializer<Edit>() {
public Edit deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
if (array.size() == 4) {
return new Edit(array.get(0).getAsInt(), array.get(1).getAsInt(), array.get(2)
.getAsInt(), array.get(3).getAsInt());
}
}
return new Edit(0, 0);
}
})
// ignore GerritForge specific AuthType "TEAMFORGE" which is unknown to Gerrit
.registerTypeAdapter(AuthType.class, new JsonDeserializer<AuthType>() {
@Override
public AuthType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String jsonString = json.getAsString();
if (jsonString != null) {
try {
return AuthType.valueOf(jsonString);
} catch (IllegalArgumentException e) {
// ignore the error since the connector does not make use of AuthType
//GerritCorePlugin.logWarning("Ignoring unkown authentication type: " + jsonString, e);
}
}
return null;
}
})
.registerTypeAdapter(approvalMapType.getType(), new JsonDeserializer<Map<Id, PatchSetApproval>>() {
@Override
public Map<Id, PatchSetApproval> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
// Gerrit 2.2: the type of PatchSetPublishDetail.given changed from a map to a list
Map<Id, PatchSetApproval> map = new HashMap<ApprovalCategory.Id, PatchSetApproval>();
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
for (Iterator<JsonElement> it = array.iterator(); it.hasNext();) {
JsonElement element = it.next();
Id key = context.deserialize(element, Id.class);
if (key.get() != null) {
// Gerrit < 2.1.x: json is map
element = it.next();
}
PatchSetApproval value = context.deserialize(element, PatchSetApproval.class);
if (key.get() == null) {
// Gerrit 2.2: json is a list, deduct key from value
key = value.getCategoryId();
}
map.put(key, value);
}
}
return map;
}
})
.setExclusionStrategies(exclustionStrategy)
.create();
}
String createRequest(int id, String xsrfKey, String methodName, Collection<Object> args) {
JsonRequest msg = new JsonRequest();
msg.method = methodName;
if (args != null) {
for (Object arg : args) {
msg.params.add(arg);
}
}
msg.id = id;
msg.xsrfKey = xsrfKey;
return gson.toJson(msg, msg.getClass());
}
<T> T parseJsonResponse(String responseMessage, Type resultType) throws GerritException {
JSonResponse response = parseResponse(responseMessage, JSonResponse.class);
if (response.error != null) {
JSonError error = gson.fromJson(response.error, JSonError.class);
throw new GerritException(error.message, error.code);
} else {
return gson.fromJson(response.result, resultType);
}
}
public <T> T parseResponse(String responseMessage, Type resultType) {
Assert.isLegal(responseMessage != null);
Assert.isLegal(!responseMessage.isEmpty());
// Gerrit 2.5 prepends the output with bogus characters
// see http://code.google.com/p/gerrit/issues/detail?id=1648
if (responseMessage.startsWith(")]}'\n")) { //$NON-NLS-1$
responseMessage = responseMessage.substring(5);
}
return gson.fromJson(responseMessage, resultType);
}
public String toJson(Object src) {
return gson.toJson(src);
}
}