//
// Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s).
// All rights reserved.
//
package openadk.generator;
import java.util.List;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
/**
* Generates ADK classes given an array of <code>DB</code> objects for each
* version of the SIF specification parsed during the parsing phase. The DB
* objects are merged into one, and from that the various .java classes are
* generated. This includes one .java class per ObjectDef; one .java class per
* EnumDef; the SIFDTD.java class; and one SIFDTD sub-class for each version of
* SIF represented in the set of parsed files (e.g. SIF10r1.java, SIF10.java,
* etc.)
*
*/
public class JavaGenerator extends CodeGenerator
{
/**
* Constructor
*/
public JavaGenerator( String srcDir, String dstDir )
{
super( srcDir, dstDir );
}
protected String getFileExtension(){
return ".java";
}
protected void writeClassHeader( PrintWriter out, ObjectDef o )
{
writeFileHeader(out);
String opackage = o.getLocalPackage();
if ( o.fName.contains("Currency")){
out.print("");
}
out.println("package openadk.library."+o.getLocalPackage()+";");
out.println();
out.println("import openadk.library.*;");
if( !o.getLocalPackage().endsWith("common") )
out.println("import openadk.library.common.*;");
if( o.getLocalPackage().endsWith("reporting"))
out.println( "import openadk.library.infra.*;");
if( o.getLocalPackage().endsWith("etranscripts")){
out.println( "import openadk.library.gradebook.*;");
out.println( "import openadk.library.student.*;");
}
out.println("import java.math.BigDecimal;");
out.println("import java.util.*;");
out.println();
writeClassComment(out,o);
out.println("public class "+o.getName() + getSuperClassSeperatorAndName( o ) );
out.println("{");
out.println( "\tprivate static final long serialVersionUID = Element.CURRENT_SERIALIZE_VERSION;" );
}
protected void writeDTDHeader( PrintWriter out, DB db, String pkg )
{
writeFileHeader(out);
if( pkg != null )
out.println("package openadk.library." + pkg + ";");
else
out.println("package openadk.library;");
out.println();
out.println("import java.util.*;");
out.println("import openadk.library.*;");
out.println("import openadk.library.common.CommonDTD;");
out.println("import openadk.library.datamodel.DatamodelDTD;");
out.println("import openadk.library.infra.InfraDTD;");
out.println("import openadk.library.impl.*;");
out.println();
}
protected void writeEnumHeader( PrintWriter out, EnumDef enumDef )
{
writeFileHeader(out);
out.println("package openadk.library."+enumDef.fPackage+";");
out.println();
out.println("import openadk.library.*;");
out.println();
}
protected void writeEnumClass(PrintWriter out, EnumDef enumDef) {
out.println("public class "+enumDef.getName()+" extends SIFEnum");
out.println("{");
out.println( "\tprivate static final long serialVersionUID = Element.CURRENT_SERIALIZE_VERSION;" );
int vv = 0;
Hashtable t = enumDef.getValues();
for( Enumeration e = t.elements(); e.hasMoreElements(); vv++ ) {
ValueDef val = (ValueDef)e.nextElement();
out.println("\t/**");
out.println("\t * " + ( val.fDesc == null ? val.fValue : val.fDesc ) + " (\""+val.fValue+"\")" );
out.println("\t */");
out.println("\tpublic static final "+enumDef.getName()+" "+symbol(val.fName)+" = " +
"new "+enumDef.getName()+"(\""+val.fValue+"\");");
out.println();
}
out.println("\t/**");
out.println("\t * Wrap an arbitrary string value in "+an(enumDef.getName(),false,false)+" object.");
out.println("\t * @param value The element/attribute value. This method does not verify");
out.println("\t * that the value is valid according to the SIF Specification.");
out.println("\t */");
out.println("\tpublic static "+enumDef.getName()+" wrap( String value ) {");
out.println("\t\treturn new "+enumDef.getName()+"( value );");
out.println("\t}");
out.println();
out.println("\tprivate "+enumDef.getName()+"( String value ) {");
out.println("\t\tsuper(value);");
out.println("\t}");
out.println("}");
}
protected void writeSDOLibraryHeader(PrintWriter out, String className ) {
out.println("public class " + className + " extends openadk.library.impl.SDOLibraryImpl");
out.println("{");
}
protected void writeClassComment( PrintWriter out, ObjectDef o )
{
out.println("/**");
out.println(" * "+o.getDesc()+"<p>");
if( o.isDraft() )
out.println("\t * <font face='verdana,helvetica' size='-1' color='red'><b>Note:</b> This is a Draft Object and is subject to change or removal prior to its final approval. Edustructures includes Draft Objects in the SIFWorks® Agent Developer Kit (ADK) for early access by developers. In the future, this class may be changed or removed for consistency with the latest approved SIF Specification.</font><p>");
out.println(" *");
out.println(" * @author Generated by adkgen");
out.println(" * @version "+o.getLatestVersion());
out.println(" * @since "+o.getEarliestVersion());
out.println(" */");
}
protected void writeDTDClassComment( PrintWriter out, DB db ) throws IOException
{
out.println("/**");
out.println(" * Represents this package to the SIF Data Objects library. This class is used internally by the ADK.<p>");
out.println(" *");
out.println(" * @author Generated by adkgen");
out.println(" */");
}
protected void writeEnumClassComment( PrintWriter out, EnumDef enumDef )
{
out.println("/**");
if( enumDef.getDesc() != null && enumDef.getDesc().length() > 0 )
{
out.println(" * " + enumDef.getDesc() + "<p>" );
}
out.println(" * Defines the set of values that can be specified whenever "+an(enumDef.getName(),false,false));
out.println(" * is used as a parameter to a method or constructor. Alternatively, the static");
out.println(" * <code>wrap</code> method can be called to encapsulate any string value in");
out.println(" * "+an(enumDef.getName(),false,false)+" object.<p>");
out.println(" *");
out.println(" * @author Generated by adkgen");
out.println(" * @version "+enumDef.getLatestVersion());
out.println(" * @since "+enumDef.getEarliestVersion());
out.println(" */");
}
protected void writeClassCtor( PrintWriter out, ObjectDef o )
{
int loopCount = ( o.isShared() ? 2 : 1 );
for( int loop = 0; loop < loopCount; loop++ )
{
if( loop == 0 )
{
out.println("\t/**");
out.println("\t * Constructor");
out.println("\t */");
if( o.isTopic() )
{
out.println("\tpublic "+o.getName()+"() {");
out.println("\t\tsuper( ADK.getSIFVersion(), "+o.getPackageQualifiedDTDSymbol()+" );");
}
else
{
out.println("\tpublic "+o.getName()+"() {");
out.println("\t\tsuper( "+o.getPackageQualifiedDTDSymbol()+" );");
}
if( o.isInfra() ){
out.println("\t}");
out.println();
out.println("\t/**");
out.println("\t * Constructor that accepts a SIFVersion");
out.println("\t * @param sifVersion The version of SIF to render this message in");
out.println("\t */");
out.println("\tpublic "+o.getName()+"( SIFVersion sifVersion ) {");
out.println("\t\tsuper( sifVersion, "+o.getPackageQualifiedDTDSymbol()+" );");
}
}
else
{
// Write out a second form of constructor that accepts an
// ElementDef as its first parameter
out.println("\t/**");
out.println("\t * This constructor is used by the SDO class library. It accepts an alternate");
out.println("\t * ElementDef constant.");
out.println("\t */");
out.println("\tprotected "+o.getName()+"( ElementDef alias ) {");
out.println("\t\tsuper( alias );");
}
out.println("\t}");
out.println();
if( o.getSuperclass().equals("SIFTime") )
{
//
// Special Case: Inherit the constructors from SIFTime
//
out.println("/**");
out.println(" * Constructs a " + o.getName() + " object from a SIF timezone and time string<p>" );
out.println(" * @param timeZone A SIF timezone value");
out.println(" * @param time A SIF time value");
out.println(" */");
out.println("public " + o.getName() + "( String timeZone, String time )");
out.println("{");
out.println("\tsuper( timeZone, time );");
out.println("\tfElementDef = SIFDTD."+o.getDTDSymbol()+";" );
out.println("}");
out.println("");
out.println("/**");
out.println(" * Constructs a " + o.getName() + " using the TimeZone of the current locale");
out.println(" * @param time A SIF time value");
out.println(" */");
out.println("public " + o.getName() + "( String time )");
out.println("{");
out.println("\tsuper( time );");
out.println("\tfElementDef = SIFDTD."+o.getDTDSymbol()+";" );
out.println("}");
out.println("");
out.println("/**");
out.println(" * Constructs a " + o.getName() + " object from a java.util.Date object using the");
out.println(" * local TimeZone as returned by Java<p>");
out.println(" * @param time The time");
out.println(" */");
out.println("public " + o.getName() + "( java.util.Date time )");
out.println("{");
out.println("\tsuper( time );");
out.println("\tfElementDef = SIFDTD."+o.getDTDSymbol()+";" );
out.println("}");
out.println("");
out.println("/**");
out.println(" * Constructs a " + o.getName() + " object from a java.util.Date object using the");
out.println(" * specified TimeZone<p>");
out.println(" * @param timeZone The TimeZone");
out.println(" * @param time The time");
out.println(" */");
out.println("public " + o.getName() + "( TimeZone timeZone, java.util.Date time )");
out.println("{");
out.println("\tsuper( timeZone, time );");
out.println("\tfElementDef = SIFDTD."+o.getDTDSymbol()+";" );
out.println("}");
out.println("");
}
//FieldType objValueType = o.getValueType();
FieldDef[] m = o.getMandatoryFields( this );
if( m.length == 0 && !o.isInfra() ){
// If this is a list container, it will have a single, repeatable
// element as a child. Use this as a constructor
FieldDef[] all = o.getAllFields();
if( all.length == 1 && all[0].isRepeatable() ){
m = all;
}
}
if( ( m.length != 0 ) && !o.isInfra() )
{
out.println("\t/**");
out.println("\t * Constructor that accepts values for all mandatory fields");
for( int i = 0; i < m.length; i++ )
out.println("\t * @param "+toProperCase(m[i].getName())+" "+m[i].getDesc());
// if( objValueType != null )
// out.println("\t * @param value The value of the element");
out.println("\t */");
out.print("\t" + ( loop == 1 ? "protected" : "public" ) + " " + o.getName() + "( ");
if( loop == 1 )
out.print( "ElementDef alias, " );
// Insert all mandatory fields as constructor parameters.
//
// Special Case: Any field that itself has one mandatory field
// will be included such that the field's single mandatory element
// type is specified instead of the field itself. For example,
// StatePr has one mandatory attribute, Code, which is of type
// StatePrCode. Rather than force agents to specify a StatePr
// object in the constructor, we use StatePrCode instead; in the
// constructor body we then automatically wrap the StatePrCode in
// a StatePr child element. Thus,
//
// Instead of:
// public SIFDataObjectClass( StatePr state, ... ) {
// addChild(state);
//
// Use:
// public SIFDataObjectClass( StatePrCode state, ... ) {
// addChild( new StatePr(state) );
//
for( int i = 0; i < m.length; i++ )
{
// Is the aforementioned Special Case applicable to this field?
String specialCaseType = toArgument(m[i]);
if( specialCaseType != null )
out.print(specialCaseType+" "+toProperCase(m[i].getName()));
else
out.print( getJavaType( m[i].getFieldType() ) + " "+toProperCase(m[i].getName()));
if( i != m.length-1 )
out.print(", ");
}
// if( objValueType != null ) {
// if( m.length > 0 ){
// out.print(", ");
// }
// out.print( getJavaType( objValueType ) + " elementValue" );
// }
out.println(" ) {");
if( o.isTopic() ) {
out.println("\t\tsuper( ADK.getSIFVersion(), "+o.getPackageQualifiedDTDSymbol()+" );");
}
else
{
if( loop == 1 ) {
out.println("\t\tsuper( alias );");
} else {
out.println("\t\tsuper( "+o.getPackageQualifiedDTDSymbol()+" );");
}
}
for( int i = 0; i < m.length; i++ )
{
// Is the aforementioned Special Case applicable to this field?
if( toArgument( m[i] ) != null )
{
String argName;
ADKDataType dataType = m[i].getFieldType().getDataType();
if( !(dataType == ADKDataType.STRING || dataType == ADKDataType.ENUM ) )
{
argName = " new " + m[i].getFieldType().getClassType() + "( " +
toProperCase( m[i].getName() ) + " )";
}
else
{
argName = toProperCase( m[i].getName() );
}
writeSetValueToField( out, o, m[i], argName );
}
else
{
writeSetValueToField( out, o, m[i], toProperCase( m[i].getName()));
}
}
// // Is the aforementioned Special Case applicable to this field?
// if( specialCase_1(m[i]) != null )
// {
// out.print("\t\t"+ setorAdd + m[i].getName() + "(");
// ADKDataType dataType = m[i].getFieldType().getDataType();
// if( !(dataType == ADKDataType.STRING || dataType == ADKDataType.ENUM ) )
// {
// out.print(" new "+m[i].getFieldType().getClassType()+"( "+toProperCase(m[i].getName())+" ) );");
// }
// else
// out.println(toProperCase(m[i].getName())+");");
// }
// else
// out.println("\t\t" + setorAdd + m[i].getName()+"("+toProperCase(m[i].getName())+");");
// }
// if( objValueType != null ) {
// out.println("\t\tsetValue( elementValue );");
// }
out.println("\t}");
out.println();
}
}
}
private void writeSetValueToField( PrintWriter out, ObjectDef o, FieldDef field, String argumentName )
{
if( field.getFieldType().getDataType() == ADKDataType.ENUM )
{
out.println( "\t\tthis.set" + field.getName() + "( " + argumentName + " );");
}
else if( field.isRepeatable() &&
( o.getElementType( fDB, this ) == ADKElementType.SIFLIST || o.getElementType( fDB, this ) == ADKElementType.SIFACTIONLIST ) )
{
out.println("\t\tthis.safeAddChild( " + field.getElementDefConst( this ) + ", " + argumentName + " );");
}
else if( !field.isComplex() || !field.isRepeatable() )
{
out.println( "\t\tthis.set" + field.getName() + "(" + argumentName + ");");
}
else
{
// TODO: Does this case ever happen ( a mandatory, repeatable field )
out.println("\t\tthis.add" + field.getName() + "( " + argumentName + " );");
}
}
protected void writeElementDefCreationLine( PrintWriter out, String dtdSymbol, String parentDtdSymbol,
boolean useElementDefAlias,String fieldName, String renderName, int sequenceNumber,
FieldType type, String localPackage, SIFVersion earliestVersion,
SIFVersion latestVersion, String flags, String typeConverter )
{
out.println("\t\t"+dtdSymbol+" = new " +
( useElementDefAlias ? "ElementDefAlias" : "ElementDefImpl" ) + "( "+
( parentDtdSymbol == null ? "null" : parentDtdSymbol ) + ",\""+
( useElementDefAlias ?
( fieldName+"\"," + ( renderName == null ? "null" : "\"" + renderName + "\"" ) + ",\"" + type.getClassType()+"\"," ) :
( fieldName+"\"," + ( renderName == null ? "null" : "\"" + renderName + "\"" ) + "," ) ) +
sequenceNumber+","+
(localPackage == null ? "null" : "SIFDTD." + localPackage ) +","+
( flags.length() == 0 ? "0" : "( " + flags + " )" ) +
",SIFVersion."+Main.versionStr( earliestVersion )+
",SIFVersion."+Main.versionStr( latestVersion )+
(typeConverter != null ? ", " + typeConverter : "") +" );");
}
protected String getTypeConverterName( FieldType type ){
String typeConverter = null;
switch( type.getDataType() ){
case STRING:
case ENUM:
typeConverter = "SIFTypeConverters.STRING";
break;
case BOOLEAN:
typeConverter = "SIFTypeConverters.BOOLEAN";
break;
case DATE:
typeConverter = "SIFTypeConverters.DATE";
break;
case TIME:
typeConverter = "SIFTypeConverters.TIME";
break;
case DATETIME:
typeConverter = "SIFTypeConverters.DATETIME";
break;
case INT:
case UINT:
typeConverter = "SIFTypeConverters.INT";
break;
case LONG:
case ULONG:
typeConverter = "SIFTypeConverters.LONG";
break;
case DECIMAL:
typeConverter = "SIFTypeConverters.DECIMAL";
break;
case FLOAT:
typeConverter = "SIFTypeConverters.FLOAT";
break;
case DURATION:
typeConverter = "SIFTypeConverters.DURATION";
}
return typeConverter;
}
protected void writeToStringOverride(PrintWriter out, FieldDef def) {
out.println("\t/**");
out.println("\t * Returns the value of the <i>" + def.getName()+ "</i> attribute" );
out.println("\t */");
out.println("\tpublic String toString() {");
out.println("\t\treturn this.get" + def.getName() + "();");
out.println("\t}");
out.println();
}
@Override
protected String getSuperClassSeperatorAndName( ObjectDef o )
{
if( o.getName().equals( "Grades" ) ){
// break
System.out.println( "Break on Annual Items" );
}
String superClass = o.getSuperclass();
if( !( superClass.equals( "SIFElement" ) || superClass.equals( "SIFActionList" ) ) )
{
return " extends " + superClass;
}
FieldDef childType = o.getRepeatableChildDef();
if( childType != null ){
ObjectDef childObject = fDB.getObject( childType.getFieldType().getClassType() );
if( childObject == null ){
throw new RuntimeException("Unable to find object definition {" +
childType.getFieldType().getClassType() + "} for member: " +
o.getName() + "." + childType.getName() );
}
FieldDef[] childKeys = childObject.getKey( this );
if( childKeys != null && childKeys.length == 1 ){
if( childObject.getField( "SIF_Action" ) != null ){
return " extends SIFActionList<" + childObject.getName() + ">";
} else {
return " extends SIFKeyedList<" + childObject.getName() + ">";
}
} else {
return " extends SIFList<" + childObject.getName() + ">";
}
} else {
FieldDef[] childKeys = o.getKey( this );
if( childKeys != null && childKeys.length == 1 ){
return " extends SIFKeyedElement";
}
return " extends SIFElement";
}
}
protected void writeAliasDefinition(PrintWriter out, String elementDefName, String flags, String aliasVer, String renderAs, String sequence ) {
out.println("\t\t"+elementDefName+".defineVersionInfo(" +
"SIFVersion.SIF" + aliasVer + ", \"" +
renderAs + "\", " +
sequence + ", " +
// ( alias.deprecated ? "FD_DEPRECATED":"(byte)0" ) +
( flags.length() == 0 ? "0" : "(" + flags + ")" ) +
"); // (SIF " + aliasVer + " alias)" );
}
protected void writeAbstractMethods( PrintWriter out, ObjectDef o )
{
// if( o.isTopic() )
// {
// out.println("\t/**");
// out.println("\t * Gets the name of the Data Object type represented by this class.");
// out.println("\t */");
// out.println("\tprotected ElementDef getObjectType() { ");
// out.println("\t\treturn ADK.DTD()."+o.getDTDSymbol()+";");
// out.println("\t}");
// out.println();
// }
FieldDef[] keys = o.getKey( this );
if( keys != null && keys.length > 0 && !o.isInfra() )
{
//
// String getKey()
//
out.println("\t/**");
out.println("\t * Gets the key of this object");
out.println("\t * @return The value of the object's Mandatory or Required attribute. If");
out.println("\t * an object has more than one such attribute, the key is a period-");
out.println("\t * delimited concatenation of the attribute values in sequential order");
out.println("\t */");
out.println("\tpublic String getKey() {");
if( keys.length == 1 ) {
out.println("\t\treturn getFieldValue( "+keys[0].getElementDefConst( this )+" );");
}
else
{
out.println("\t\tStringBuilder b = new StringBuilder();");
for( int i = 0; i < keys.length; i++ ) {
out.println("\t\tb.append( getFieldValue( "+keys[i].getElementDefConst( this )+" ) );");
if( i != keys.length-1 )
out.println("\t\tb.append('.');");
}
out.println("\t\treturn b.toString();");
}
out.println("\t}");
out.println();
//
// ElementDef[] getKeyFields
//
out.println("\t/**");
out.println("\t * Gets the metadata fields that make up the key of this object");
out.println("\t * @return an array of metadata fields that make up the object's key" );
out.println("\t */");
out.println("\tpublic ElementDef[] getKeyFields() {");
out.print("\t\treturn new ElementDef[] { " );
for( int i = 0; i < keys.length; i++ ) {
if( i > 0){
out.print( ", " );
}
out.print( keys[i].getElementDefConst( this ) );
}
out.println(" };");
out.println("\t}");
out.println();
}
}
protected void writeDTDAbstractMethods( PrintWriter out )
{
// Not implemented
}
protected void writeDtdLoad( PrintWriter out )
{
out.println("\tpublic void load()");
}
protected void writeDTDTableUpdates( PrintWriter out, DB db, String pkg )
{
out.println("\tpublic void addElementMappings( Map<String, ElementDef> dtdMap )");
out.println("\t{");
HashSet<String> dictionaryItems = new HashSet<String>();
ObjectDef[] objects = db.getObjects();
Arrays.sort( objects,
new Comparator()
{
public int compare( Object obj1, Object obj2 ){
ObjectDef objectDef1 = (ObjectDef)obj1;
ObjectDef objectDef2 = (ObjectDef)obj2;
return objectDef1.getName().compareTo( objectDef2.getName() );
}
}
);
for( ObjectDef obj : objects )
{
String tag = obj.getName();
if( !obj.getLocalPackage().equals(pkg) ){
continue;
}
out.println();
out.println("\t\t // "+ tag + " aliases and fields" );
if( obj.getRenderAs() != null ){
out.println("\t\tdtdMap.put(\""+obj.getRenderAs()+"\","+tag.toUpperCase()+" );");
}
out.println("\t\tdtdMap.put(\""+tag+"\","+tag.toUpperCase()+" );");
// Check for aliases
Map<String, List<SIFVersion>> aliases = obj.getAliases();
if( aliases != null ){
for( String renderAs: aliases.keySet() ){
List<SIFVersion> versions = aliases.get( renderAs );
out.print("\t\t// alias for version(s) : " );
for( SIFVersion version : versions ){
out.print( version.toString() );
out.print( "," );
}
out.println();
out.println("\t\tdtdMap.put(\""+renderAs+"\","+tag.toUpperCase()+" );");
}
}
writeDTDTableUpdatesForObject( out, db, obj, dictionaryItems );
if( obj.isTopic() ){
out.println("\t\tdtdMap.put(\""+tag+"_SIF_ExtendedElements\","+tag.toUpperCase()+"_SIF_EXTENDEDELEMENTS );");
out.println("\t\tdtdMap.put(\""+tag+"_SIF_Metadata\","+tag.toUpperCase()+"_SIF_METADATA );");
}
}
out.println("\t}");
}
@Override
protected void writeSingleDTDTableUpdate(PrintWriter out, String tagCombination, String dtdConstName, String addComment) {
out.println("\t\tdtdMap.put(\""+ tagCombination +"\"," + dtdConstName + " );" + ( addComment != null ? " // " + addComment : "" ) );
}
private String getJavaType( FieldType type )
{
if( type.isComplex() ){
return type.getClassType();
} else if( type.isEnum() ){
return type.getEnum();
} else {
switch( type.getDataType() ){
case STRING:
case ENUM:
case SIFVERSION:
return "String";
case BOOLEAN:
return "Boolean";
case DATE:
case DATETIME:
case TIME:
return "Calendar";
case INT:
case UINT:
return "Integer";
case LONG:
case ULONG:
return "Long";
case DECIMAL:
return "BigDecimal";
case FLOAT:
return "Float";
case DURATION:
return "javax.xml.datatype.Duration";
}
return null;
}
}
protected String getADKSimpleType( ADKDataType dataType ){
switch( dataType ){
case BOOLEAN:
return "SIFBoolean";
case DATE:
return "SIFDate";
case DATETIME:
return "SIFDateTime";
case TIME:
return "SIFTime";
case DECIMAL:
return "SIFDecimal";
case FLOAT:
return "SIFFloat";
case DURATION:
return "SIFDuration";
case INT:
case UINT:
return "SIFInt";
case LONG:
case ULONG:
return "SIFLong";
case SIFVERSION:
case STRING:
return "SIFString";
}
return null;
}
protected void writeSimpleField( PrintWriter out, ObjectDef o, FieldDef f )
{
if( ( o.getFlags() & ObjectDef.FLAG_NO_SIFDTD ) != 0 || ( f.getFlags() & FieldDef.FLAG_NO_SIFDTD ) != 0 )
return;
FieldType ft = f.getFieldType();
ADKDataType adkType = ft.getDataType();
String javaType = getJavaType( ft );
out.println("\t/**");
String aore = null;
if( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) != 0 ) {
out.println("\t * Gets the value of the <code>"+f.getName()+"</code> attribute.");
aore = "attribute";
} else {
out.println("\t * Gets the value of the <code><"+f.getName()+"></code> element.");
aore = "element";
}
writeJavadoc(out,o,f,aore);
out.println("\t *");
out.println("\t * @return The <code>"+f.getName()+"</code> "+aore+" of this object.");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
if( f.getFieldType().isEnum() ) {
out.println("\tpublic String get"+f.getName()+"() { ");
out.println("\t\treturn getFieldValue( "+f.getElementDefConst( this )+" );");
}
else
{
out.println("\tpublic " + javaType + " get"+f.getName()+"() { ");
// if( nullCheck )
// {
// out.println("\t\tString __nullchk__ = getFieldValue( SIFDTD."+f.getDTDSymbol()+" );\r\n\t\treturn __nullchk__ == null ? null : " + castT+" __nullchk__ " + castT2 + ";" );
// }
// else
out.println("\t\treturn (" + javaType + ") getSIFSimpleFieldValue( "+f.getElementDefConst( this )+" );");
}
out.println("\t}");
out.println();
out.println("\t/**");
if( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) != 0 ) {
out.println("\t * Sets the value of the <code>"+f.getName()+"</code> attribute.");
} else {
if( f.isRepeatable() ) {
out.println("\t * Adds a new <code><"+f.getName()+"></code> child element.");
} else {
out.println("\t * Sets the value of the <code><"+f.getName()+"></code> element.");
}
}
writeJavadoc(out,o,f,aore);
out.println("\t *");
if( f.getFieldType().isEnum() ) {
out.println("\t * @param value A constant defined by the <code>"+f.getFieldType().getEnum()+"</code> class");
} else {
out.println("\t * @param value A <code>"+ javaType +"</code> object");
}
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic void set"+f.getName()+"( "+ javaType +" value ) { ");
if( f.getFieldType().isEnum() ) {
out.println( "\t\tsetField( "+f.getElementDefConst( this )+ ", value );" );
}else{
out.println( "\t\tsetFieldValue( "+f.getElementDefConst( this )+ ", new " + getADKSimpleType( adkType ) + "( value ), value );" );
}
out.println("\t}");
out.println();
if( f.getFieldType().isEnum() )
{
out.println("\t/**");
if( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) != 0 ) {
out.println("\t * Sets the value of the <code>"+f.getName()+"</code> attribute as a String.");
} else {
out.println("\t * Sets the value of the <code><"+f.getName()+"></code> element as a String.");
}
writeJavadoc(out,o,f,aore);
out.println("\t *");
out.println("\t * @param value The value as a String");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic void set"+f.getName()+"( String value ) { ");
out.println("\t\tsetField( "+f.getElementDefConst( this )+", value );");
out.println("\t}");
out.println();
}
}
protected void writeComplexField( PrintWriter out, ObjectDef o, FieldDef f, ObjectDef type )
throws GeneratorException
{
// NOTE: New to ADK 2.0 is the SIFAction list and SIFList base classes that use generics
// to provide a useful collection API. This class does not generate as many get or set
// accessors for these elements because the underlying base class does it for them.
ADKElementType elementType = o.getElementType( fDB, this );
boolean parentIsList = false;
if( ( elementType == ADKElementType.SIFACTIONLIST || elementType == ADKElementType.SIFLIST ) ){
parentIsList = true;
}
if( ( o.getFlags() & ObjectDef.FLAG_NO_SIFDTD ) != 0 || ( f.getFlags() & FieldDef.FLAG_NO_SIFDTD ) != 0 )
return;
// Determine if the 'type' object has a name that differs from the
// implementation class name - that is, uses an ElementDefAlias instead
// of ElementDef. Country and StatePr are two that fall into this
// category. If any do, then the following action will be taken (Country
// is used as the example):
//
// 1. The method "setCountryOfResidency( Country country )" will not be
// written out because that would require the user to properly
// construct a Country object with the CountryOfResidency
//
// 2. Write out the "setCountryOfResidency( CountryCode code )" method
// instead, but the body is written to call the
// "Country( SIFDTD.DEMOGRAPHICS_COUNTRYOFRESIDENCY, code )"
// constructor instead of the usual "Country( code )" constructor
//
boolean useElementDefAlias = !f.getSuperclass().equals(f.getName());
if( useElementDefAlias ) {
ObjectDef test = fDB.getObject( f.getSuperclass() );
useElementDefAlias = ( test != null && test.isShared() );
}
FieldDef[] m = type.getMandatoryFields( this );
String aore = null;
String setOrAdd = f.isRepeatable() ? "add" : "set";
if( !parentIsList )
{
out.println("\t/**");
if( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) != 0 ) {
out.println("\t * Sets the value of the <code>"+f.getName()+"</code> attribute.");
aore = "attribute";
} else {
if( f.isRepeatable() ) {
out.println("\t * Adds a new <code><"+f.getName()+"></code> child element.");
} else {
out.println("\t * Sets the value of the <code><"+f.getName()+"></code> element.");
}
aore = "element";
}
writeJavadoc(out,o,f,aore);
out.println("\t *");
if( f.getFieldType().isEnum()) {
out.println("\t * @param value A constant defined by the <code>" + f.getFieldType().getEnum() + "</code> class");
} else {
out.println("\t * @param value A <code>"+type.getName()+"</code> object");
}
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic void " + setOrAdd + f.getName()+"( "+ type.getName() +" value ) { ");
if( !f.isRepeatable() )
out.println("\t\tremoveChild( "+f.getElementDefConst( this )+" );");
out.println("\t\taddChild( " + f.getElementDefConst( this ) + ", value);");
out.println("\t}");
out.println();
}
if( !f.getFieldType().isEnum() && ( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) == 0 ) && m.length != 0 && !o.isInfra() )
{
// Write a setObjectType() convenience method; this one has all of
// the parameters of the parameterized constructor for ObjectType.
// Instead of writing "setObjectType( new ObjectType(a,b,c) )",
// an agent can simply write "setObjectType( a,b,c )"
//
out.println("\t/**");
if( f.isRepeatable() ) {
out.println("\t * Adds a new <code><"+f.getName()+"></code> repeatable element.");
} else {
out.println("\t * Sets the value of the <code><"+f.getName()+"></code> child element.");
}
if( !useElementDefAlias ) {
out.println("\t * This form of <code>set"+f.getName()+"</code> is provided as a convenience method");
out.println("\t * that is functionally equivalent to the version of <code>set"+f.getName()+"</code>");
out.println("\t * that accepts a single <code>"+type.getName()+"</code> object.");
}
out.println("\t *");
//FieldType objValueType = type.getValueType();
for( int i = 0; i < m.length; i++ )
out.println("\t * @param "+toProperCase(m[i].getName())+" "+m[i].getDesc());
// if( objValueType != null )
// out.println("\t * @param value The value of this "+type.getName());
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.print("\tpublic void " + setOrAdd + f.getName()+"( ");
for( int i = 0; i < m.length; i++ )
{
String specialCaseType = toArgument(m[i]);
if( specialCaseType != null )
out.print(specialCaseType+" "+toProperCase(m[i].getName()));
else
out.print( getJavaType( m[i].getFieldType() ) + " " + toProperCase(m[i].getName()));
if( i != m.length-1 )
out.print(", ");
}
// if( m.length > 0 ){
// if( objValueType != null ){
// out.print(", ");
// out.print( getJavaType( objValueType ) + " value");
// }
// }
out.println(" ) {");
if( useElementDefAlias )
{
if( !f.isRepeatable() )
out.println( "\t\tremoveChild( " + f.getElementDefConst( this ) + ");" );
out.print( "\t\taddChild( " + f.getElementDefConst( this ) + ", new "+type.getName()+"( " + f.getElementDefConst( this ) + ", " );
}
else
{
if( !f.isRepeatable() )
out.println( "\t\tremoveChild( " + f.getElementDefConst( this ) + ");" );
out.print("\t\taddChild( " + f.getElementDefConst( this ) + ", new " + type.getName() + "( ");
}
for( int i = 0; i < m.length; i++ ) {
out.print(toProperCase(m[i].getName()));
if( i != m.length-1 )
out.print(", ");
}
// if( m.length > 0 ){
// if( objValueType != null ){
// out.print(", ");
// out.print("value");
// }
// }
out.println(" ) );");
out.println("\t}");
out.println();
}
if( f.isRepeatable() )
{
FieldDef[] keys = type.getKey( this );
if( keys.length != 0 )
{
//
// removeObjectType( String key )
//
out.println("\t/**");
out.println("\t * Removes "+an(f.getFieldType().getClassType(),false,true)+" object instance. More than one instance can be defined for this object because it is a repeatable field element.");
out.println("\t *");
for( int i = 0; i < keys.length; i++ ) {
out.println("\t * @param "+toProperCase(keys[i].getName())+" Identifies the "+type.getName()+" object to remove by its "+keys[i].getName()+" value");
}
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.print("\tpublic void remove"+f.getName()+"( ");
for( int i = 0; i < keys.length; i++ ) {
out.print( getJavaType( keys[i].getFieldType() ) + " "+toProperCase(keys[i].getName()));
if( i != keys.length-1 )
out.print(", ");
}
out.println(" ) { ");
out.print("\t\tremoveChild( "+f.getElementDefConst( this )+", new String[] { ");
for( int i = 0; i < keys.length; i++ )
{
if( keys[i].getFieldType().getDataType() == ADKDataType.INT )
out.print("String.valueOf(" + toProperCase(keys[i].getName()) + ")" );
else
out.print(toProperCase(keys[i].getName())+".toString()");
if( i != keys.length-1 )
out.print(",");
}
out.println(" } );");
out.println("\t}");
out.println();
//
// getObjectType( String key )
//
out.println("\t/**");
out.println("\t * Gets "+an(f.getFieldType().getClassType(),false,true)+" object instance. More than one instance can be defined for this object because it is a repeatable field element.");
out.println("\t *");
for( int i = 0; i < keys.length; i++ ) {
out.println("\t * @param "+toProperCase(keys[i].getName())+" Identifies the "+type.getName()+" object to return by its \""+keys[i].getName()+"\" attribute value");
}
out.println("\t * @return "+an(type.getName(),true,true)+" object");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.print("\tpublic "+type.getName()+" get"+f.getName()+"( ");
for( int i = 0; i < keys.length; i++ ) {
out.print( getJavaType( keys[i].getFieldType() ) + " "+toProperCase(keys[i].getName()));
if( i != keys.length-1 )
out.print(", ");
}
out.println(" ) { ");
out.print("\t\treturn ("+type.getName()+")getChild( "+f.getElementDefConst( this )+", new String[] { ");
for( int i = 0; i < keys.length; i++ )
{
if( keys[i].getFieldType().getDataType() == ADKDataType.INT )
out.print("String.valueOf(" + toProperCase(keys[i].getName()) + ")" );
else
out.print(toProperCase(keys[i].getName())+".toString()");
if( i != keys.length-1 )
out.print(",");
}
out.println(" } );");
out.println("\t}");
out.println();
}
// GET/SET repeatable elements are now handled by the base class,
// SIF_Repeatable element list
String pluralTypeName = plural(f.getName());
//
// ObjectType[] getObjectTypes()
//
// e.g.
// List<? extends SIFElement> v = getChildrenV( SIFDTD.CIRCTX_FINEINFO);
// FineInfo[] cvt = new FineInfo[v.size()];
// v.toArray(cvt);
// return cvt;
//
out.println("\t/**");
out.println("\t * Gets all <code>"+f.getFieldType().getClassType()+"</code> object instances. More than one instance can be defined for this object because it is a repeatable field element.");
out.println("\t *");
out.println("\t * @return An array of <code>"+type.getName()+"</code> objects");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic "+type.getName()+"[] get"+pluralTypeName+"() {");
out.println("\t\tList<SIFElement> v = getChildList( " +f.getElementDefConst( this )+");");
out.println("\t\t"+type.getName()+"[] cvt = new "+type.getName()+"[v.size()];");
out.println("\t\tv.toArray(cvt);");
out.println("\t\treturn cvt;");
out.println("\t}");
out.println();
//
// setObjectTypes( ObjectType[] )
//
out.println("\t/**");
out.println("\t * Sets an array of <code>"+f.getFieldType().getClassType()+"</code> objects. All existing " );
out.println("\t * <code>"+f.getFieldType().getClassType()+"</code> instances " );
out.println("\t * are removed and replaced with this list. Calling this method with the " );
out.println("\t * parameter value set to null removes all <code>"+plural(f.getFieldType().getClassType())+"</code>.");
out.println("\t *");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic void set"+pluralTypeName+"( "+type.getName()+"[] "+pluralTypeName.toLowerCase()+" ) {");
out.println("\t\tsetChildren( "+f.getElementDefConst( this )+", "+pluralTypeName.toLowerCase()+" );");
out.println("\t}");
out.println();
}
else
{
out.println("\t/**");
if( ( f.getFlags() & FieldDef.FLAG_ATTRIBUTE ) != 0 ) {
out.println("\t * Gets the value of the <code>"+f.getName()+"</code> attribute.");
} else {
out.println("\t * Gets the value of the <code><"+f.getName()+"></code> element.");
}
writeJavadoc(out,o,f,aore);
out.println("\t *");
out.println("\t * @return "+an(type.getName(),true,true)+" object");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic "+type.getName()+" get"+f.getName()+"() { ");
out.println("\t\treturn ("+type.getName()+")getChild( "+f.getElementDefConst( this )+");");
out.println("\t}");
out.println();
out.println("\t/**");
out.println("\t * Removes the <code>"+f.getName()+"</code> child element previously created by calling <code>set" + f.getName() + "</code>");
out.println("\t *");
//out.println("\t * @version "+f.getLatestVersion());
out.println("\t * @since "+f.getEarliestVersion());
out.println("\t */");
out.println("\tpublic void remove"+f.getName()+"() { ");
out.println("\t\tremoveChild( "+f.getElementDefConst( this )+" );");
out.println("\t}");
out.println();
}
}
protected void writeJavadoc( PrintWriter out, ObjectDef o, FieldDef f, String attrOrElement )
{
if( f.getDesc() != null && f.getDesc().length() > 0 )
out.println("\t* <p> The SIF specification defines the meaning of this "+attrOrElement+" as: \r\n"
+ "\t* <i>\"" + f.getDesc() + "\"</i><p>");
Alias[] uniqueTags = f.getUniqueTagAliases();
if( uniqueTags.length > 1 )
{
StringBuilder b = new StringBuilder();
b.append("\t * This " + attrOrElement + " is known by more than one tag name depending on the version of SIF in use. The ADK will use the tag names shown below when parsing and rendering " + attrOrElement + "s of this kind.<p>\r\n");
b.append("\t * <table width='50%' border='1'><tr><td align='center'><font face='verdana,helvetica' size='-1'>Version</font></td><td align='center'><font face='verdana,helvetica' size='-1'>Tag</font></td></tr>\r\n" );
int diffs = 0;
for( Alias alias : uniqueTags )
{
if( !alias.getTag().equals( f.getTag() ) )
diffs++;
b.append("\t * <tr>");
b.append("\t * <td><font face='verdana,helvetica' size='-1'>SIF" + alias.getVersion() + " (and greater)</font></td><td>\"" + alias.getTag() + "\"</td>");
b.append("\t * </tr>\r\n");
}
b.append("\t * </table><p>");
if( diffs > 0 )
{
out.println(b.toString());
}
}
}
protected String toProperCase( String str )
{
return toJavaCase( str );
}
/**
* Formats a string using Java conventions
* such that all preceding characters of the string up to
* the first capitalized character are all lowercase. For example, "fooBar",
* "FooBar", and "FOOBar" will all be returned as "fooBar".
*/
public static String toJavaCase( String str )
{
StringBuffer b = new StringBuffer();
b.append( Character.toLowerCase(str.charAt(0)) );
char ch = 0;
boolean flatten = true;
for( int i = 1; i < str.length(); i++ )
{
ch = str.charAt(i);
if( flatten && ( i+1 < str.length() && !Character.isLowerCase(ch) && Character.isLowerCase(str.charAt(i+1) ))) {
flatten = false;
b.append( str.substring(i) );
break;
}
if( ch != '_' )
b.append( flatten ? Character.toLowerCase(ch) : ch );
}
return b.toString();
}
protected String symbol(String s) {
StringBuffer b = new StringBuffer();
if( Character.isDigit(s.charAt(0)) )
b.append("_");
char ch = 0;
for( int i = 0; i < s.length(); i++ ) {
ch = s.charAt(i);
if( ch == '-' )
b.append("_");
else
b.append( ch );
}
return b.toString();
}
/**
* Writes a single ElementDef const line to the specified PrintWriter
* @param out
* @param o
*/
protected void writeElementDefConst(PrintWriter out, String comment, String constName ) {
out.println("\t/** " + comment + " */");
out.println("\tpublic static ElementDef " + constName + " = null;");
}
@Override
protected void writeSIFDTDClass(DB database, String dir, DB packageDB) throws IOException {
PrintWriter out = null;
String fn = dir+File.separator + "SIFDTD" + getFileExtension();
System.out.println("- Generating: "+fn);
try
{
File md = new File(dir);
md.mkdirs();
out = new PrintWriter( new FileWriter(fn),true );
writeDTDHeader(out,null,null);
writeExtras(out,"SIFDTD_comments.txt");
out.println("public class SIFDTD implements DTD");
out.println("{");
for( int i = 0; i < InfraMessages.length; i++ ) {
out.println("\t/** Identifies the "+InfraMessages[i]+" element */");
out.println("\tpublic static final byte MSGTYP_"+InfraMessages[i].substring(4).toUpperCase()+" = "+(i+1)+";");
out.println();
}
// Special case
out.println("\t// SIF_Message mapping used internally by SIFParser");
out.println("\tpublic static ElementDef SIF_MESSAGE = new ElementDefImpl(null,\"SIF_Message\",null,0,\"impl\",SIFVersion.SIF11, SIFVersion.LATEST );");
out.println("\tpublic static ElementDef SIF_MESSAGE_VERSION = new ElementDefImpl( SIFDTD.SIF_MESSAGE,\"Version\",null,1,SIFDTD.infra,(ElementDefImpl.FD_FIELD),SIFVersion.SIF11, SIFVersion.LATEST );");
out.println();
out.println("\t// Declare all object and field elements defined by all versions of SIF");
out.println("\t// supported by the class framework. Definitions are created by version-");
out.println("\t// dependent subclasses of SIFDTD (e.g. SIF10r1, SIF10r2, etc.)");
// Write out the ElementDef statics for each object
ObjectDef[] o = database.getObjects();
Arrays.sort( o, new Comparator<ObjectDef>()
{
public int compare( ObjectDef o1, ObjectDef o2 ) {
return o1.getDTDSymbol().compareTo( o2.getDTDSymbol() );
}
}
);
int dtdItemCount = 2;
for( int k = 0; k < o.length; k++ )
{
if( ( o[k].getFlags() & ObjectDef.FLAG_NO_SIFDTD ) == 0 )
{
dtdItemCount++;
}
}
ArrayList<String> publicPackages = new ArrayList<String>();
out.println();
out.println("\t// Package names that comprise the SIF Data Objects library");
for( String packageName : packageDB.getDefinitionFileKeysSet() ) {
DefinitionFile packageFile = packageDB.getDefinitionFile( packageName );
out.println( "\t/** The name of the " + packageFile.getFriendlyName() + " package */" );
out.println("\tpublic static final String "+ packageName + " = \"" + packageName + "\";");
if( !( packageName.equalsIgnoreCase( "infra" ) ||
packageName.equalsIgnoreCase( "common") ) ){
publicPackages.add( packageName );
}
}
out.println();
out.println("\t// Constants identifying each package in the SIF Data Objects library");
out.println( "\t/** All SDO libraries */" );
out.println("\tpublic static final int SDO_ALL = 0xFFFFFFFF;");
out.println( "\t/** No SDO libraries */" );
out.println("\tpublic static final int SDO_NONE = 0x00000000;");
out.println( "\t// These are always loaded regardless of what the user specifies.");
out.println( "\t// They are considered \"built-in\" SDO libraries but under the hood they're ");
out.println( "\t// treated just like any other SDO package.");
out.println("\tprivate static final int SDO_INFRA = 0x40000000;");
out.println("\tprivate static final int SDO_COMMON = 0x80000000;");
StringBuilder allPackages = new StringBuilder();
int packageConst = 1;
for( String packageName : publicPackages ) {
DefinitionFile packageFile = packageDB.getDefinitionFile( packageName );
out.println( "\t/** Identifies the " + packageFile.getFriendlyName() + " package */" );
out.println("\tpublic static final int SDO_"+ packageName.toUpperCase() + " = 0x00000" + Integer.toHexString( packageConst ) + ";");
packageConst *=2;
allPackages.append( packageName );
allPackages.append( ", " );
}
out.println();
out.println( "\t/** An array of all available package names */" );
out.println("\tprivate static final String[] sLibNames = new String[] { " + allPackages.substring( 0, allPackages.length() -2 ) + " };");
String nmspc = packageDB.getDefinitionFile( publicPackages.get( 0 ) ).fNamespace;
// Strip off the trailing "2.x"
nmspc = nmspc.substring( 0, nmspc.lastIndexOf( '/' ) );
out.println();
out.println( "\t/** The base xmlns for this edition of the ADK without the version */" );
out.println("\tpublic static final String XMLNS_BASE=\"" + nmspc + "\";" );
out.println();
writeDTDAbstractMethods(out);
out.println("\tpublic static HashMap<String,ElementDef> sElementDefs = new HashMap<String,ElementDef>(" + String.valueOf( dtdItemCount ) + ");");
out.println("\tstatic {");
// Special case
out.println("\t\tsElementDefs.put(\"SIF_Message\",SIF_MESSAGE );");
out.println("\t\tsElementDefs.put(\"SIF_Message_Version\",SIF_MESSAGE_VERSION );");
out.println("\t};");
out.println();
out.println("\t// Maps infrastructure messages to type codes");
out.println("\tprotected static HashMap<String,Byte> sTypemap = new HashMap<String,Byte>();");
out.println("\tstatic {");
for( int i = 0; i < InfraMessages.length; i++ )
out.println("\t\tsTypemap.put(\""+InfraMessages[i]+"\", new Byte((byte)"+(i+1)+") );");
out.println("\t};");
out.println();
out.println("\t// Infrastructure messages indexed by type codes");
out.println("\tprotected static String[] sTagmap = new String[] {");
for( int i = 0; i < InfraMessages.length; i++ )
out.println("\t\t\""+InfraMessages[i]+"\",");
out.println("\t};");
out.println();
writeExtras( out, "SIFDTD_template.txt" );
writeClassFooter(out);
}
finally
{
if( out != null ) {
try {
out.close();
} catch( Exception e ) {
}
}
}
}
}