/*******************************************************************************
* Copyright (c) 2017 Red Hat.
* 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:
* Red Hat - Initial Contribution
*******************************************************************************/
package org.eclipse.che.api.languageserver.generator;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.eclipse.che.api.languageserver.generator.DtoGenerator.INDENT;
import static org.eclipse.che.api.languageserver.generator.DtoGenerator.dtoName;
;
/**
* This class generates property conversions from regular lsp4j classes to dto classes.
* Used to convert responses from the backend language servers for che rmi usage.
*
* @author Thomas Mäder
*/
public class ToDtoGenerator extends ConversionGenerator {
private Set<Class<? extends Object>> classes;
public ToDtoGenerator(Set<Class<? extends Object>> classes) {
this.classes = classes;
}
public static void generateMakeDto(String indent, PrintWriter out, Set<Class<? extends Object>> classes) {
out.println(indent + "public static final Object makeDto(Object obj) {");
for (Class<? extends Object> clazz : classes) {
out.println(indent + INDENT + String.format("if (obj instanceof %1$s) {", clazz.getName()));
out.println(indent + INDENT + INDENT + String.format("return new %1$s((%2$s)obj);", dtoName(clazz), clazz.getName()));
out.println(indent + INDENT + "}");
}
out.println(indent + INDENT + "return obj;");
out.println(indent + "}");
}
public void generateToDto(String indent, PrintWriter out, Class<?> receiverClass, Method m, String objectName) {
String varName = fieldName(m) + "Val";
String valueAccess = objectName + "." + getterName(receiverClass, m) + "()";
Type paramType = m.getGenericParameterTypes()[0];
if (getRawClass(paramType).isPrimitive()) {
generateToDto(indent + INDENT, out, varName, valueAccess, paramType);
out.println(String.format(indent + INDENT + "%1$s((%2$s)%3$s);", m.getName(), paramType.getTypeName(), varName));
} else {
out.println(indent + String.format("if (%1$s == null) {", valueAccess));
out.println(indent + INDENT + String.format("%1$s((%2$s)null);", m.getName(), paramType.getTypeName()));
out.println(indent + "} else {");
generateToDto(indent + INDENT, out, varName, valueAccess, paramType);
out.println(String.format(indent + INDENT + "%1$s((%2$s)%3$s);", m.getName(), paramType.getTypeName(), varName));
out.println(indent + "}");
}
}
private void generateToDto(String indent, PrintWriter out, String varName, String valueAccess, Type paramType) {
Class<?> rawClass = getRawClass(paramType);
if (List.class.isAssignableFrom(rawClass)) {
generateListConversion(indent + INDENT, out, varName, valueAccess, paramType);
} else if (Map.class.isAssignableFrom(rawClass)) {
generateMapConversion(indent + INDENT, out, varName, valueAccess, paramType);
} else if (Either.class.isAssignableFrom(rawClass)) {
generateEitherConversion(indent + INDENT, out, varName, valueAccess, paramType);
} else {
out.println(String.format(indent + "%1$s %2$s = %3$s;", rawClass.getName(), varName,
dtoValueExpression(rawClass, valueAccess)));
}
}
private void generateEitherConversion(String indent, PrintWriter out, String varName, String valueAccess,
Type paramType) {
String innerName = varName + "e";
out.println(indent + String.format("%1$s %2$s;", paramType.getTypeName(), varName));
out.println(indent + String.format("if (%1$s.getLeft() != null) {", valueAccess));
generateToDto(indent + INDENT, out, innerName, valueAccess + ".getLeft()", EitherUtil.getLeftDisjointType(paramType));
out.println(indent + INDENT + String.format("%1$s= Either.forLeft(%2$s);", varName, innerName));
out.println(indent + "} else {");
generateToDto(indent + INDENT, out, innerName, valueAccess + ".getRight()", EitherUtil.getRightDisjointType(paramType));
out.println(indent + INDENT + String.format("%1$s= Either.forRight(%2$s);", varName, innerName));
out.println(indent + "}");
}
private void generateMapConversion(String indent, PrintWriter out, String varName, String valueAccess,
Type paramType) {
ParameterizedType genericType = (ParameterizedType)paramType;
Type containedType = genericType.getActualTypeArguments()[1];
Type valueType = genericType.getActualTypeArguments()[1];
String containedName = varName + "X";
out.println(indent + String.format("HashMap<String, %1$s> %2$s= new HashMap<String, %3$s>();",
containedType.getTypeName(), varName, containedType.getTypeName()));
out.println(String.format(indent + "for (Entry<String, %1$s> %2$s : %3$s.entrySet()) {",
valueType.getTypeName(), containedName, valueAccess));
generateToDto(indent + INDENT, out, varName + "Y", containedName + ".getValue()", valueType);
out.println(indent + INDENT
+ String.format("%1$s.put(%2$s, %3$s);", varName, containedName + ".getKey()", varName + "Y"));
out.println(indent + "}");
}
private void generateListConversion(String indent, PrintWriter out, String varName, String valueAccess,
Type paramType) {
Type containedType = containedType(paramType);
out.println(indent + String.format("ArrayList<%1$s> %2$s= new ArrayList<%3$s>();", containedType.getTypeName(), varName,
containedType.getTypeName()));
String containedName = varName + "X";
out.println(String.format(indent + "for (%1$s %2$s : %3$s) {", containedType.getTypeName(), containedName,
valueAccess));
generateToDto(indent + INDENT, out, varName + "Y", containedName, containedType);
out.println(indent + INDENT + String.format("%1$s.add(%2$s);", varName, varName + "Y"));
out.println(indent + "}");
}
private String dtoValueExpression(Class<?> t, String value) {
if (isDtoClass(t)) {
return String.format("new %1$s(%2$s)", dtoName(t), value);
} else {
return String.format("(%1$s)makeDto(%2$s);", t.getName(), value);
}
}
private boolean isDtoClass(Class<?> t) {
return classes.contains(t);
}
}