/* * Copyright 2010 Zhihua (Dennis) Jiang * * Licensed 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 com.gwtmobile.persistence.rebind; import java.util.List; import com.google.gwt.core.ext.typeinfo.JMethod; public class InstanceGenerator implements ClassGenerator { final GenUtils utils; final String requestedClassName; final String generatedClassName; final List<JMethod> getters; final List<JMethod> hasManyRels; final List<JMethod> hasOneRels; public InstanceGenerator(GenUtils utils, String requestedClassName, String generatedClassName, List<JMethod> getters, List<JMethod> hasManyRels, List<JMethod> hasOneRels) { this.utils = utils; this.requestedClassName = requestedClassName; this.generatedClassName = generatedClassName; this.getters = getters; this.hasManyRels = hasManyRels; this.hasOneRels = hasOneRels; } @Override public void classSetup() { utils.addVariable("private", "JavaScriptObject", "nativeObject"); } @Override public void generateClass() { utils.generateMethod("public", null, requestedClassName + "Impl", new String[][] {{"JavaScriptObject", "nativeObject"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("this.nativeObject = nativeObject;"); } }); utils.generateMethod("public", "JavaScriptObject", "getNativeObject", null, new MethodGenerator() { @Override public void generateMethod() { utils.println("return nativeObject;"); } }); utils.generateMethod("public", "String", "getId", null, new MethodGenerator() { @Override public void generateMethod() { utils.println("return getId(nativeObject);"); } }); utils.generateNativeMethod("private", "String", "getId", new String[][]{{"JavaScriptObject", "nativeObject"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("return nativeObject.id;"); } }); utils.generateMethod("public", "<T extends Persistable> void", "fetch", new String[][]{ {"Transaction", "transaction"}, {"Entity<T>", "entity"}, {"ScalarCallback<T>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("EntityInternal<T> entityInternal = (EntityInternal<T>)entity;"); utils.println("fetch(transaction, entityInternal.getEntityName(), entityInternal, callback, this, nativeObject);"); } }); utils.generateMethod("public", "<T extends Persistable> void", "fetch", new String[][]{ {"Entity<T>", "entity"}, {"ScalarCallback<T>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("fetch(null, entity, callback);"); } }); utils.generateNativeMethod("private", " <T extends Persistable> void", "fetch", new String[][]{ {"Transaction", "transaction"}, {"String", "property"}, {"EntityInternal<T>", "entity"}, {"ScalarCallback<T>", "callback"}, {requestedClassName + "Impl", "self"}, {"JavaScriptObject", "nativeObject"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("nativeObject.fetch($wnd.persistence, transaction, property, function(result) {"); utils.sw().indent(); utils.println("self.@%s.%s.%sImpl::processFetchCallback(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/gwtmobile/persistence/client/EntityInternal;Lcom/gwtmobile/persistence/client/ScalarCallback;)(result, entity, callback);", utils.getPackageName(requestedClassName), generatedClassName, requestedClassName); utils.sw().outdent(); utils.println("});"); } }); utils.generateMethod("private", "<T extends Persistable> void", "processFetchCallback", new String[][]{ {"JavaScriptObject", "result"}, {"EntityInternal<T>", "entity"}, {"ScalarCallback<T>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("callback.onSuccess(entity.newInstance(result));"); } }); utils.generateMethod("public", "void", "selectJSON", new String[][]{ {"Transaction", "transaction"}, {"String[]", "propertySpec"}, {"ScalarCallback<String>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("JsArrayString jsArray = null;"); utils.println("if (propertySpec != null) {"); utils.sw().indent(); utils.println("jsArray = (JsArrayString) JavaScriptObject.createArray();"); utils.println("for (int i = 0; i < propertySpec.length; i++) {"); utils.println("String spec = propertySpec[i];"); utils.println("jsArray.set(i, spec);"); utils.sw().outdent(); utils.println("}"); utils.sw().outdent(); utils.println("}"); utils.println("selectJSON(transaction, jsArray, callback, this, nativeObject);"); } }); utils.generateMethod("public", "void", "selectJSON", new String[][]{ {"String[]", "propertySpec"}, {"ScalarCallback<String>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("selectJSON(null, propertySpec, callback);"); } }); utils.generateNativeMethod("private", "void", "selectJSON", new String[][]{ {"Transaction", "transaction"}, {"JsArrayString", "propertySpec"}, {"ScalarCallback<String>", "callback"}, {requestedClassName + "Impl", "self"}, {"JavaScriptObject", "nativeObject"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("nativeObject.selectJSON(transaction, propertySpec, function(result) {"); utils.sw().indent(); utils.println("var resultJson = $wnd.JSON.stringify(result);"); utils.println("self.@%s.%s.%sImpl::processStringCallback(Ljava/lang/String;Lcom/gwtmobile/persistence/client/ScalarCallback;)(resultJson, callback);", utils.getPackageName(requestedClassName), generatedClassName, requestedClassName); utils.sw().outdent(); utils.println("});"); } }); utils.generateMethod("private", "void", "processStringCallback", new String[][]{ {"String", "result"}, {"ScalarCallback<String>", "callback"}}, new MethodGenerator() { @Override public void generateMethod() { utils.println("callback.onSuccess(result);"); } }); for (final JMethod getter : getters) { //TODO: is getter method always public? final String returnTypeName = getter.getReturnType().getSimpleSourceName(); final boolean isDateReturnType = returnTypeName.equals("Date"); final boolean isPrimitiveReturnType = getter.getReturnType().isPrimitive() != null; final boolean isCharReturnType = returnTypeName.equals("char"); final boolean isJsonReturnType = utils.isSubclassOf(getter.getReturnType(), "JSONValue"); utils.generateMethod("public", returnTypeName, getter.getName(), null, new MethodGenerator(){ @Override public void generateMethod() { if (isDateReturnType) { utils.println("long value = (long)" + getter.getName() + "(nativeObject);"); //TODO: assume that the actual date is not "the epoch" for now. utils.println("return (value == 0) ? null : new Date(value);"); } else if (isJsonReturnType) { utils.println("String value = " + getter.getName() + "(nativeObject);"); utils.println("return (value == null) ? null : (%s) JSONParser.parse(value);", returnTypeName); } else { utils.println("return " + getter.getName() + "(nativeObject);"); } }}); utils.generateNativeMethod("private", isDateReturnType ? "double" : isJsonReturnType ? "String" : returnTypeName, getter.getName(), new String[][]{{"JavaScriptObject", "nativeObject"}}, new MethodGenerator(){ @Override public void generateMethod() { utils.println("var value = nativeObject." + getter.getName().substring(3) + ";"); //CHAR in SQLite has TEXT affinity. if (isCharReturnType) { utils.println("return (value == null || value.length == 0) ? 0 : value.charCodeAt(0);"); } else if (isPrimitiveReturnType) { utils.println("return (value == null) ? 0 : value;"); } else if (isDateReturnType) { //return Date.getTime() as double. Can't pass long to Java. utils.println("return (value == null) ? 0 : value.getTime();"); } else if (isJsonReturnType) { utils.println("return (value == null) ? null : JSON.stringify(value);"); } else { utils.println("return value;"); } }}); utils.generateMethod("public", "void", "set" + getter.getName().substring(3), new String[][]{{returnTypeName, "value"}}, new MethodGenerator(){ @Override public void generateMethod() { if (isDateReturnType) { utils.println("set" + getter.getName().substring(3) + "(value == null ? 0 : value.getTime(), nativeObject);"); } else if (isJsonReturnType) { utils.println("set" + getter.getName().substring(3) + "(value == null ? null : value.toString(), nativeObject);"); } else { utils.println("set" + getter.getName().substring(3) + "(value, nativeObject);"); } }}); utils.generateNativeMethod("private", "void", "set" + getter.getName().substring(3), new String[][]{ {isDateReturnType ? "double" : isJsonReturnType ? "String" : returnTypeName, "value"}, {"JavaScriptObject", "nativeObject"}}, new MethodGenerator(){ @Override public void generateMethod() { if (isDateReturnType) { utils.println("nativeObject." + getter.getName().substring(3) + " = (value == 0) ? null : new Date(value);"); } else if (isJsonReturnType) { utils.println("nativeObject." + getter.getName().substring(3) + " = (value == null) ? null : JSON.parse(value);"); } else if (isCharReturnType) { utils.println("nativeObject." + getter.getName().substring(3) + " = String.fromCharCode(value);"); } else { utils.println("nativeObject." + getter.getName().substring(3) + " = value;"); } }}); } for (final JMethod hasManyRel : hasManyRels) { utils.generateMethod("public", hasManyRel.getReturnType().getParameterizedQualifiedSourceName(), hasManyRel.getName(), null, new MethodGenerator(){ @Override public void generateMethod() { utils.println("return hasMany" + hasManyRel.getName().substring(3) + ".newCollection(" + hasManyRel.getName() + "(nativeObject));"); }}); utils.generateNativeMethod("private", "JavaScriptObject", hasManyRel.getName(), new String[][]{{"JavaScriptObject", "nativeObject"}}, new MethodGenerator(){ @Override public void generateMethod() { utils.println("return nativeObject." + hasManyRel.getName().substring(3) + ";"); }}); } for (final JMethod hasOneRel : hasOneRels) { utils.generateMethod("public", hasOneRel.getReturnType().getSimpleSourceName(), hasOneRel.getName(), null, new MethodGenerator(){ @Override public void generateMethod() { utils.println("return hasOne" + hasOneRel.getName().substring(3) + ".newInstance(" + hasOneRel.getName() + "(nativeObject));"); }}); utils.generateNativeMethod("private", "JavaScriptObject", hasOneRel.getName(), new String[][]{{"JavaScriptObject", "nativeObject"}}, new MethodGenerator(){ @Override public void generateMethod() { utils.println("return nativeObject." + hasOneRel.getName().substring(3) + ";"); }}); utils.generateMethod("public", "void", "set" + hasOneRel.getName().substring(3), new String[][]{{hasOneRel.getReturnType().getSimpleSourceName(), "value"}}, new MethodGenerator(){ @Override public void generateMethod() { utils.println("set" + hasOneRel.getName().substring(3) + "(((PersistableInternal)(value)).getNativeObject(), nativeObject);"); }}); utils.generateNativeMethod("private", "void", "set" + hasOneRel.getName().substring(3), new String[][]{ {"JavaScriptObject", "value"}, {"JavaScriptObject", "nativeObject"}}, new MethodGenerator(){ @Override public void generateMethod() { utils.println("nativeObject." + hasOneRel.getName().substring(3) + " = value;"); }}); } } }