/*
* Copyright 2013 cruxframework.org.
*
* 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 org.cruxframework.crux.core.rebind.database;
import java.util.Date;
import org.cruxframework.crux.core.client.db.annotation.DatabaseDef.Empty;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.core.rebind.AbstractProxyCreator;
import org.cruxframework.crux.core.rebind.CruxGeneratorException;
import org.cruxframework.crux.core.rebind.context.RebindContext;
import org.cruxframework.crux.core.rebind.rest.JSonSerializerProxyCreator;
import org.cruxframework.crux.core.utils.JClassUtils;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayMixed;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public abstract class AbstractKeyValueProxyCreator extends AbstractProxyCreator
{
protected final JClassType targetObjectType;
protected final JClassType integerType;
protected final JClassType doubleType;
protected final JClassType stringType;
protected final JClassType dateType;
protected final JClassType emptyType;
protected final String objectStoreName;
protected final String[] keyPath;
protected final String serializerVariable;
public AbstractKeyValueProxyCreator(RebindContext context, JClassType targetObjectType, String objectStoreName, String[] keyPath)
{
super(context, false);
this.objectStoreName = objectStoreName;
this.keyPath = keyPath;
this.targetObjectType = targetObjectType;
if (JClassUtils.isSimpleType(targetObjectType))
{
throw new CruxGeneratorException("Simple types are not allowed as row in Crux Database. Create an wrapper Object to your value. ObjectStoreName["+objectStoreName+"]");
}
this.stringType = context.getGeneratorContext().getTypeOracle().findType(String.class.getCanonicalName());
this.integerType = context.getGeneratorContext().getTypeOracle().findType(Integer.class.getCanonicalName());
this.doubleType = context.getGeneratorContext().getTypeOracle().findType(Double.class.getCanonicalName());
this.dateType = context.getGeneratorContext().getTypeOracle().findType(Date.class.getCanonicalName());
this.emptyType = context.getGeneratorContext().getTypeOracle().findType(Empty.class.getCanonicalName());
this.serializerVariable = "serializer";
}
@Override
protected void generateProxyFields(SourcePrinter srcWriter) throws CruxGeneratorException
{
if (!isEmptyType())
{
String serializerName = new JSonSerializerProxyCreator(context, targetObjectType).create();;
srcWriter.println("private "+serializerName+" "+serializerVariable+" = new "+serializerName+"();");
}
}
protected void validatePrimaryKeyPath(JClassType targetObjectType, String objectStoreName, String[] keyPath)
{
if (keyPath == null)
{
throw new CruxGeneratorException("Invalid KeyPath. ObjectStoreName["+objectStoreName+"]");
}
for (String k : keyPath)
{
if (!k.matches("\\w*"))
{
throw new CruxGeneratorException("Invalid KeyPath. ObjectStoreName["+objectStoreName+"]");
}
JType jType = JClassUtils.getTypeForProperty(k, targetObjectType);
if (jType == null || jType.isPrimitive() != null)
{
throw new CruxGeneratorException("Invalid keyPath for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]. Crux does not accept primitive types as object store keys");
}
}
}
protected boolean hasCompositeKey()
{
return (keyPath.length > 1) && (!isEmptyType());
}
protected void generateFromNativeKeyMethod(SourcePrinter srcWriter)
{
generateFromNativeKeyMethod(srcWriter, keyPath);
}
protected void generateFromNativeValueMethod(SourcePrinter srcWriter, String[] keyPath)
{
generateFromNativeMethod(srcWriter, "fromNativeValue", keyPath);
}
protected void generateFromNativeKeyMethod(SourcePrinter srcWriter, String[] keyPath)
{
generateFromNativeMethod(srcWriter, "fromNativeKey", keyPath);
}
protected void generateFromNativeMethod(SourcePrinter srcWriter, String methodName, String[] keyPath)
{
srcWriter.println("private Object[] "+methodName+"("+JsArrayMixed.class.getCanonicalName()+" key){");
srcWriter.println("Object[] result = new Object[key.length()];");
int i=0;
for (String key : keyPath)
{
String getterMethod = JClassUtils.getGetterMethod(key, targetObjectType);
if (StringUtils.isEmpty(getterMethod))
{
throw new CruxGeneratorException("Invalid keyPath for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
JType jType = JClassUtils.getReturnTypeFromMethodClass(targetObjectType, getterMethod, new JType[]{});
if (jType.equals(stringType))
{
srcWriter.println("result["+i+"] = key.getString("+i+");");
}
else if (jType.equals(integerType) || (jType.equals(JPrimitiveType.INT)))
{
srcWriter.println("result["+i+"] = (int)key.getNumber("+i+");");
}
else if (jType.equals(doubleType) || (jType.equals(JPrimitiveType.DOUBLE)))
{
srcWriter.println("result["+i+"] = key.getNumber("+i+");");
}
else if (jType.equals(dateType))
{
srcWriter.println("result["+i+"] = new "+Date.class.getCanonicalName()+"((long)key.getNumber("+i+"));");
}
else
{
throw new CruxGeneratorException("Invalid key type for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
i++;
}
srcWriter.println("return result;");
srcWriter.println("}");
srcWriter.println();
}
protected void generateGetNativeKeyMethod(SourcePrinter srcWriter, String[] keyPath, String methodName)
{
srcWriter.println("private void "+methodName+"("+getKeyTypeName(keyPath)+" key, "+JsArrayMixed.class.getCanonicalName()+" result){");
if (keyPath.length > 1)
{
srcWriter.println("if (key == null){");
srcWriter.println("result.push((String)null);");
srcWriter.println("return;");
srcWriter.println("}");
}
int i=0;
for (String key : keyPath)
{
String keyVar;
if (keyPath.length > 1)
{
keyVar = "key["+i+"]";
}
else
{
keyVar = "key";
}
srcWriter.println("if ("+keyVar+" == null){");
srcWriter.println("result.push((String)null);");
srcWriter.println("}");
srcWriter.println("else{");
JType jType = JClassUtils.getTypeForProperty(key, targetObjectType);
if (jType == null)
{
throw new CruxGeneratorException("Invalid keyPath for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
if (jType.equals(stringType))
{
srcWriter.println("result.push((String)"+keyVar+");");
}
else if (jType.equals(integerType) || (jType.equals(JPrimitiveType.INT)))
{
if (keyPath.length > 1)
{
srcWriter.println("result.push((Integer)"+keyVar+");");
}
else
{
srcWriter.println("result.push((int)"+keyVar+");");
}
}
else if (jType.equals(doubleType) || (jType.equals(JPrimitiveType.DOUBLE)))
{
if (keyPath.length > 1)
{
srcWriter.println("result.push((Double)"+keyVar+");");
}
else
{
srcWriter.println("result.push((double)"+keyVar+");");
}
}
else if (jType.equals(dateType))
{
srcWriter.println("result.push((double)(("+Date.class.getCanonicalName()+")"+keyVar+").getTime());");
}
else
{
throw new CruxGeneratorException("Invalid key type for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
srcWriter.println("}");
i++;
}
srcWriter.println("}");
}
protected void generateGetNativeKeyMethod(SourcePrinter srcWriter)
{
srcWriter.println("private "+JsArrayMixed.class.getCanonicalName()+" getNativeKey(Object[] key){");
srcWriter.println(JsArrayMixed.class.getCanonicalName()+ " result = "+JsArrayMixed.class.getCanonicalName()+".createArray().cast();");
srcWriter.println("getNativeKey(key, result);");
srcWriter.println("return result;");
srcWriter.println("}");
srcWriter.println();
generateGetNativeKeyMethod(srcWriter, keyPath, "getNativeKey");
}
protected String getTargetObjectClassName()
{
if (isEmptyType())
{
return JavaScriptObject.class.getCanonicalName();
}
return targetObjectType.getParameterizedQualifiedSourceName();
}
protected String getKeyTypeName()
{
return getKeyTypeName(keyPath);
}
protected String getKeyTypeName(String[] keyPath)
{
if (isEmptyType())
{
return JsArrayMixed.class.getCanonicalName();
}
if (keyPath.length >= 2)
{
return "Object[]";
}
else if (keyPath.length == 1)
{
JType jType = JClassUtils.getTypeForProperty(keyPath[0], targetObjectType);
if (jType == null)
{
throw new CruxGeneratorException("Invalid keyPath for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
if (jType.equals(stringType))
{
return "String";
}
else if (jType.equals(integerType) || (jType.equals(JPrimitiveType.INT)))
{
return "Integer";
}
else if (jType.equals(doubleType) || (jType.equals(JPrimitiveType.DOUBLE)))
{
return "Double";
}
else if (jType.equals(dateType))
{
return Date.class.getCanonicalName();
}
else
{
throw new CruxGeneratorException("Invalid key type for objectStore ["+targetObjectType.getParameterizedQualifiedSourceName()+"]");
}
}
else
{
throw new CruxGeneratorException("can not create an objectStore without a key definition. ObjectStore["+objectStoreName+"].");
}
}
protected boolean isEmptyType()
{
return targetObjectType.isAssignableTo(emptyType);
}
protected abstract void generateGetKeyRangeFactoryMethod(SourcePrinter srcWriter, String parentName);
}