package pt.ist.fenixframework.dml;
import java.io.PrintWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Iterator;
import java.util.List;
import pt.ist.fenixframework.dml.runtime.Relation;
public class ValueTypeSerializationGenerator extends DefaultCodeGenerator {
public static final String SERIALIZER_CLASS_PACKAGE = "pt.ist.fenixframework";
public static final String SERIALIZER_CLASS_SIMPLE_NAME = "ValueTypeSerializer";
public static final String SERIALIZER_CLASS_FULL_NAME = SERIALIZER_CLASS_PACKAGE + "." + SERIALIZER_CLASS_SIMPLE_NAME;
public static final String SERIALIZATION_METHOD_PREFIX = "serialize$";
public static final String DESERIALIZATION_METHOD_PREFIX = "deSerialize$";
protected PrintWriter out;
public ValueTypeSerializationGenerator(CompilerArgs compArgs, DomainModel domainModel) {
super(compArgs, domainModel);
}
public static String getSerializedFormTypeName(ValueType vt) {
List<ExternalizationElement> extElems = vt.getExternalizationElements();
if (extElems.size() == 0) { // built-in type do not have externalizers
return vt.getFullname();
} else if (extElems.size() == 1) {
// It's just a wrapper. So, our serialized form is the same as our component's
return getSerializedFormTypeName(extElems.get(0).getType());
} else {
// Alas, we need a full-blown SerializedForm for this one
return makeSerializationValueTypeName(vt);
}
}
@Override
public void generateCode() {
// create the ValueTypeSerializationGenerator before starting the "standard" generation.
File file = new File(getBaseDirectoryFor(SERIALIZER_CLASS_PACKAGE), SERIALIZER_CLASS_SIMPLE_NAME + ".java");
try {
file.getParentFile().mkdirs();
this.out = new PrintWriter(new FileWriter(file), true);
} catch (java.io.IOException ioe) {
throw new Error("Can't open file" + file);
}
generateFilePreamble(SERIALIZER_CLASS_PACKAGE, this.out);
newline(out);
printWords(out, "public", "final", "class", SERIALIZER_CLASS_SIMPLE_NAME);
newBlock(out);
generateValueTypeSerializations();
closeBlock(out);
}
protected void generateValueTypeSerializations() {
for (ValueType vt : getDomainModel().getAllValueTypes()) {
if (!(vt.isBuiltin() || vt.isEnum())) {
println(out, "");
print(out, "// VT: " + vt.getDomainName() + " serializes as " + getSerializedFormTypeName(vt));
List<ExternalizationElement> extElems = vt.getExternalizationElements();
if (extElems.size() > 1) { // because 1-externalizer VTs unwrap and use their component's type
generateValueTypeSerializableForm(vt);
}
generateValueTypeSerialization(vt);
generateValueTypeDeSerialization(vt);
}
}
}
protected void generateValueTypeSerializableForm(ValueType vt) {
onNewline(out);
print(out, "public static final class " + makeSerializationValueTypeName(vt) + " implements java.io.Serializable");
newBlock(out);
onNewline(out);
println(out, "private static final long serialVersionUID = 1L;");
generateSlots(vt);
generateConstructor(vt);
closeBlock(out);
}
protected void generateSlots(ValueType vt) {
List<ExternalizationElement> extElems = vt.getExternalizationElements();
for (ExternalizationElement extElem : extElems) {
ValueType extElemVt = extElem.getType();
if (extElemVt.isBuiltin() || extElemVt.isEnum()) {
generateSlotDeclaration(out, extElemVt.getFullname(), makeSlotName(extElem));
} else {
generateSlotDeclaration(out, getSerializedFormTypeName(extElemVt),
extElem.getMethodName().replace('.', '_'));
}
}
}
protected void generateConstructor(ValueType vt) {
onNewline(out);
printMethod(out, "private", "", makeSerializationValueTypeName(vt), makeArg(vt.getFullname(), "obj"));
startMethodBody(out);
List<ExternalizationElement> extElems = vt.getExternalizationElements();
for (ExternalizationElement extElem : extElems) {
onNewline(out);
ValueType extElemVt = extElem.getType();
printWords(out, "this." + makeSlotName(extElem), "=",
applyExternalizationIfRequired(applyExternalizerTo(extElem, "obj"), extElemVt));
print(out, ";");
}
endMethodBody(out);
}
protected String applyExternalizerTo(ExternalizationElement extElem, String expr) {
String extMethodName = extElem.getMethodName();
// parametric types require cast, so we always cast
String cast = "(" + extElem.getType().getFullname() + ")";
return (extMethodName.contains("."))
? cast + extMethodName + "(" + expr + ")"
: cast + expr + "." + extMethodName + "()";
}
protected String applyExternalizationIfRequired(String expr, ValueType vt) {
if ((vt.isBuiltin() || vt.isEnum())) {
return expr;
} else {
return SERIALIZATION_METHOD_PREFIX + makeSafeValueTypeName(vt) + "(" + expr + ")";
}
}
public static String makeSerializationValueTypeName(ValueType vt) {
return "Serialized$" + makeSafeValueTypeName(vt);
}
public static String makeSafeValueTypeName(ValueType vt) {
return vt.getDomainName().replace('.', '$');
}
protected String makeSlotName(ExternalizationElement extElem) {
return extElem.getMethodName().replace('.', '_');
}
protected void generateValueTypeSerialization(ValueType vt) {
onNewline(out);
printMethod(out, "public static final", getSerializedFormTypeName(vt),
SERIALIZATION_METHOD_PREFIX + makeSafeValueTypeName(vt),
makeArg(vt.getFullname(), "obj"));
startMethodBody(out);
print(out, "return ");
if (DomainModel.isNullableType(vt)) {
print(out, "(obj == null) ? null : ");
}
if (vt.getExternalizationElements().size() == 1) {
ExternalizationElement extElem = vt.getExternalizationElements().get(0);
ValueType extElemVt = extElem.getType();
print(out, applyExternalizationIfRequired(applyExternalizerTo(extElem, "obj"), extElemVt));
} else {
print(out, "new " + makeSerializationValueTypeName(vt) + "(obj)");
}
print(out, ";");
endMethodBody(out);
}
protected void generateValueTypeDeSerialization(ValueType vt) {
onNewline(out);
printMethod(out, "public static final", vt.getFullname(),
DESERIALIZATION_METHOD_PREFIX + makeSafeValueTypeName(vt),
makeArg(getSerializedFormTypeName(vt) , "obj"));
startMethodBody(out);
String internalizationMethodName = vt.getInternalizationMethodName();
if (internalizationMethodName == null) { // class constructor
internalizationMethodName = "new " + vt.getFullname();
} else if (!internalizationMethodName.contains(".")) { // static method in the same class
internalizationMethodName = vt.getFullname() + "." + internalizationMethodName;
}
print(out, "return ");
if (DomainModel.isNullableTypeFullName(getSerializedFormTypeName(vt))) {
print(out, "(obj == null) ? null : ");
}
print(out, "(" + vt.getFullname() + ")");
print(out, internalizationMethodName + "(");
boolean firstArg = true;
List<ExternalizationElement> extElems = vt.getExternalizationElements();
if (extElems.size() == 1) {
ExternalizationElement extElem = extElems.get(0);
ValueType extElemVt = extElem.getType();
if (extElemVt.isBuiltin() || extElemVt.isEnum()) {
print(out, "obj");
} else {
print(out, DESERIALIZATION_METHOD_PREFIX + makeSafeValueTypeName(extElemVt) + "(obj)");
}
} else {
for (ExternalizationElement extElem : extElems) {
if (firstArg) {
firstArg = false;
} else {
print(out, ", ");
}
ValueType extElemVt = extElem.getType();
if (extElemVt.isBuiltin() || extElemVt.isEnum()) {
print(out, "obj." + makeSlotName(extElem));
} else {
// note that extElems.size() > 1 because of the outer if statment
print(out, DESERIALIZATION_METHOD_PREFIX + makeSafeValueTypeName(extElemVt) + "(obj." +
extElem.getMethodName().replace('.', '_') + ")");
}
}
}
print(out, ");");
endMethodBody(out);
}
}