package org.fusesource.restygwt.rebind;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import org.fusesource.restygwt.client.Dispatcher;
import org.fusesource.restygwt.client.MethodCallback;
import org.fusesource.restygwt.client.Resource;
import org.fusesource.restygwt.client.RestServiceProxy;
import org.fusesource.restygwt.client.callback.CallbackAware;
import org.fusesource.restygwt.rebind.util.OnceFirstIterator;
import static org.fusesource.restygwt.rebind.DirectRestServiceInterfaceClassCreator.DIRECT_REST_SERVICE_SUFFIX;
public class DirectRestServiceClassCreator extends DirectRestBaseSourceCreator {
public static final String DIRECT_REST_IMPL_SUFFIX = DIRECT_REST_SERVICE_SUFFIX + "Impl";
public static final String VOID_QUALIFIED_NAME = "void";
public DirectRestServiceClassCreator(TreeLogger logger, GeneratorContext context, JClassType source) {
super(logger, context, source, DIRECT_REST_IMPL_SUFFIX);
}
@Override
protected ClassSourceFileComposerFactory createComposerFactory() throws UnableToCompleteException {
return createClassSourceComposerFactory(JavaSourceCategory.CLASS,
null,
new String[]{
source.getParameterizedQualifiedSourceName(),
CallbackAware.class.getCanonicalName(),
RestServiceProxy.class.getCanonicalName()
}
);
}
@Override
protected void generate() throws UnableToCompleteException {
super.generate();
createRestyServiceField();
createDelegateRestServiceProxyMethods();
createCallbackSupportMethodsAndField();
createServiceMethods();
}
private void createRestyServiceField() {
String sourceName = getName(source) + DIRECT_REST_SERVICE_SUFFIX;
p("private " + sourceName + " service = com.google.gwt.core.client.GWT.create(" + sourceName + ".class);");
}
private void createDelegateRestServiceProxyMethods() {
String resourceClass = Resource.class.getCanonicalName();
String dispatcherClass = Dispatcher.class.getCanonicalName();
String restServiceProxyClass = RestServiceProxy.class.getCanonicalName();
p("public final void setResource(" + resourceClass + " resource) {").i(1)
.p("((" + restServiceProxyClass + ")service).setResource(resource);").i(-1)
.p("}");
p("public final " + resourceClass + " getResource() {").i(1)
.p("return ((" + restServiceProxyClass + ")service).getResource();").i(-1)
.p("}");
p("public final void setDispatcher(" + dispatcherClass + " resource) {").i(1)
.p("((" + restServiceProxyClass + ")service).setDispatcher(resource);").i(-1)
.p("}");
p("public final " + dispatcherClass + " getDispatcher() {").i(1)
.p("return ((" + restServiceProxyClass + ")service).getDispatcher();").i(-1)
.p("}");
}
private void createCallbackSupportMethodsAndField() {
createCallbackField();
createCallbackSetter();
createVerifyCallbackMethod();
}
private void createServiceMethods() {
for (JMethod method : source.getInheritableMethods()) {
generateMethod(method);
}
}
private void generateMethod(JMethod method) {
p( getMethodDeclaration(method) + " {").i(1);
generateCallVerifyCallback(method);
generateCallServiceMethod(method);
generateReturnNull(method);
i(-1).p("}");
}
private String getMethodDeclaration(JMethod method) {
return method.getReadableDeclaration(false, true, false, false, true);
}
private void generateCallVerifyCallback(JMethod method) {
p("verifyCallback(\"" + method.getName() + "\");");
}
private void generateCallServiceMethod(JMethod method) {
StringBuilder stringBuilder = new StringBuilder();
OnceFirstIterator<String> comma = new OnceFirstIterator<String>("", ", ");
stringBuilder.append("service.")
.append(method.getName())
.append("(");
for (JParameter parameter : method.getParameters()) {
stringBuilder.append(comma.next())
.append(parameter.getName());
}
stringBuilder.append(comma.next());
if (isOverlayMethod(method)) {
stringBuilder.append("(org.fusesource.restygwt.client.OverlayCallback) this.callback");
} else {
stringBuilder.append("this.callback");
}
stringBuilder.append(");");
p(stringBuilder.toString());
}
private void generateReturnNull(JMethod method) {
if (isVoidMethod(method)) {
// check void first since JPrimitiveType will consider void to be a primitive
return;
} else if (method.getReturnType().isPrimitive() != null) {
JPrimitiveType primitiveType = method.getReturnType().isPrimitive();
p("return " + primitiveType.getUninitializedFieldExpression() + ";");
} else {
p("return null;");
}
}
private static boolean isVoidMethod(JMethod method) {
return VOID_QUALIFIED_NAME.equals(method.getReturnType().getQualifiedBinaryName());
}
private void createCallbackField() {
p("private " + MethodCallback.class.getCanonicalName() + " callback;");
}
private void createCallbackSetter() {
p( "public void setCallback(" + MethodCallback.class.getCanonicalName() + " callback) {").i(1)
.p("this.callback = callback;").i(-1)
.p("}");
}
private void createVerifyCallbackMethod() {
p( "public void verifyCallback(String methodName) {").i(1)
.p("if (this.callback == null) {").i(1)
.p("throw new IllegalArgumentException(" +
"\"You need to call this service with REST.withCallback(new MethodCallback<..>(){..}).call(service).\" + " +
"methodName + " +
"\"(..) and not try to access the service directly\");").i(-1)
.p("}").i(-1)
.p("}");
}
}