import java.io.IOException ;
import java.io.OutputStreamWriter ;
import java.io.Writer ;
import de.tuhh.sts.codegen.ModelException ;
import de.tuhh.sts.codegen.java.* ;
import de.tuhh.sts.codegen.java.code.* ;

/**
 * Test for the java code generation toolkit.
 * @author Hans-Werner Sehring
 */

public class Test {

    static public void main (String [] args) throws ModelException, IOException {

        new Test () ;

    }// main

    /**
     * Constructor initializing a set of classes and starting code generation.
     * @throws ModelException on an attempt to produce a malformed model
     * @throws IOException    when failing to write out source code
     */
    public Test () throws ModelException, IOException {

        // create a model
        JavaModel model = new JavaModel () ;

        // create a package to put classes in
        JavaPackage pkg = new JavaPackage (model, "de.tuhh.sts.test") ;

        // create some interface
        JavaInterface intf1 = new JavaInterface (
            model,
            pkg,
            JavaVisibility.PUBLIC,
            "AnInterface") ;
        JavaAbstractMethod methodi11 = new JavaAbstractMethod (
            JavaVisibility.PUBLIC,
            model.VOID,
            "aMethod",
            new JavaVariable [] {
                new JavaVariable ((JavaType)model.getType ("short"), "param1"),
                new JavaVariable ((JavaType)model.getType ("java.lang.String"), "param2")
            },
            new AbstractJavaClass [0]) ;
        intf1.addMethod (methodi11) ;

        // create some abstract class
        JavaAbstractClass cls1 = new JavaAbstractClass (
            model,
            pkg,
            JavaVisibility.DEFAULT,
            "Class1",
            new JavaInterface [] { intf1 }) ;
        JavaInterface actionInterface =
            (JavaInterface)model.getType (javax.swing.Action.class) ;
        JavaClass actionEventClass =
            (JavaClass)model.getType (java.awt.event.ActionEvent.class) ;
        JavaMethodBody body = new JavaMethodBody (new Statement [] {
            new ReturnStatement (
                new AnonymousClassConstructorCall (
                    actionInterface,
                    new JavaMethod [] {
                        new JavaMethod (
                            JavaVisibility.PUBLIC,
                            model.VOID,
                            "actionPerformed",
                            new JavaVariable [] {
                                new JavaVariable (actionEventClass, "evt")
                            },
                            new JavaMethodBody ())
            }))
        }) ;
        JavaConstructor con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls1,
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls1.addConstructor (con) ;
        JavaAbstractMethod am = new JavaAbstractMethod (
            JavaVisibility.DEFAULT, model.VOID, "anAbstractMethod") ;
        cls1.addMethod (am) ;
        cls1.addMethod (methodi11) ;
        VariableDeclaration varDecl =
            new VariableDeclaration (model.DOUBLE, "y") ;
        JavaVariable var = varDecl.getVariable () ;
        JavaVariable param = new JavaVariable (model.DOUBLE, "x") ;
        body = new JavaMethodBody (new Statement [] {
            varDecl,
            new Assignment (
                new VariableReference (var),
                new MultiplicationExpression (
                    new DivisionExpression (
                        new VariableReference (param),
                        new IntegerNumber (7)),
                    new SubtractionExpression (
                        new FloatNumber (1),
                        new VariableReference (param)))),
            new VariableDeclaration (
                model.LONG,
                "l",
                new ModuloExpression (
                    new LongNumber (100),
                    new ShortNumber ((short)3)))
        }) ;
        JavaMethod m = new JavaMethod (
            JavaVisibility.PROTECTED,
            false,
            model.VOID,
            "someComputation",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls1.addMethod (m) ;

        // create some concrete class with some members
        JavaClass cls2 = new JavaClass (model, pkg, JavaVisibility.PUBLIC, "Class2") ;
        // static fields
        JavaClass hashtableClass =
            (JavaClass)model.getType (java.util.Hashtable.class) ;
        JavaField field21 = new JavaField (
            JavaVisibility.PUBLIC,
            true,
            hashtableClass,
            "sf1") ;
        cls2.addClassField (field21) ;
        // fields
        JavaField field22 = new JavaField (
            JavaVisibility.PRIVATE,
            (JavaType)model.getType ("int"),
            "f1") ;
        cls2.addField (field22) ;
        JavaField field23 = new JavaField (
            JavaVisibility.PRIVATE,
            hashtableClass,
            "f2") ;
        cls2.addField (field23) ;
        JavaClass stringClass =
            (JavaClass)model.getType (java.lang.String.class) ;
        JavaField field24 = new JavaField (
            JavaVisibility.PROTECTED,
            stringClass,
            "f3",
            new MethodCall (
                new StringLiteral ("hello"),
                stringClass.getMethod ("substring", new JavaType [] {
                    model.INT,
                    model.INT
                }),
                new Expression [] {
                    new IntegerNumber (1),
                    new IntegerNumber (4)
                })) ;
        cls2.addField (field24) ;
        // static constructor
        body = new JavaMethodBody (new Statement [] {
            new Assignment (new FieldReference (field22), new IntegerNumber (7)),
            new Assignment (
                new FieldReference (field23),
                new ConstructorCall (
                    hashtableClass,
                    new Expression [] { new IntegerNumber (4) }))
        }) ;
        con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls2,
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls2.setStaticConstructor (con) ;
        // constructors
        param = new JavaVariable ((JavaType)model.getType ("int"), "i") ;
        body = new JavaMethodBody (new Statement [] {
            new Assignment (
                new FieldReference (field22),
                new IntegerNumber (7)),
            new Assignment (
                new FieldReference (field23),
                new ConstructorCall (
                    hashtableClass,
                    new Expression [] {
                        new VariableReference (param)
                    }))
        }) ;
        con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls2,
            new JavaVariable [] { param },
            new AbstractJavaClass [0],
            body) ;
        cls2.addConstructor (con) ;
        // static methods
        body = new JavaMethodBody (new Statement [] {
            new Assignment (
                new FieldReference (field24),
                new FieldReference (field22))
        }) ;
        JavaMethod method21 = new JavaMethod (
            JavaVisibility.PUBLIC,
            false,
            model.VOID,
            "m1",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls2.addClassMethod (method21) ;
        // methods
        body = new JavaMethodBody () ;
        JavaMethod method22 = new JavaMethod (
            JavaVisibility.PUBLIC,
            false,
            model.VOID,
            "m1",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        method22.setCode (new JavaMethodBody (
            new IfElseStatement (
                new EqualExpression (
                    new FieldReference (field24),
                    new StringLiteral ("hello world")),
                 new ReturnStatement (),
                 new MethodCall (method22))
        )) ;
        body = new JavaMethodBody (new Statement [] {
            new Assignment (
                new FieldReference (field24),
                new FieldReference (field22)),
            new MethodCall (method22)
        }) ;
        cls2.addMethod (method22) ;
        JavaClass math = (JavaClass)model.getType ("Math") ;
        VariableDeclaration vd = new VariableDeclaration (
            true,
            model.FLOAT,
            "fv",
            new MethodCall (
                new JavaClassReference (math),
                math.getMethod ("sqrt", new JavaType [] { model.DOUBLE }),
                new Expression [] { new DoubleNumber (28.25) })) ;
        body = new JavaMethodBody (new CompoundStatement (new Statement [] {
            vd,
            new ReturnStatement (
                new AdditionExpression (
                    new VariableReference (vd.getVariable ()),
                    new FloatNumber ((float)17.5)))
        })) ;
        JavaMethod method23 = new JavaMethod (
            JavaVisibility.PRIVATE,
            false,
            model.VOID,
            "m2",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls2.addMethod (method23) ;

        // create some concrete class of the abstract class
        JavaClass cls3 = new JavaClass (
            model,
            pkg,
            JavaVisibility.PUBLIC,
            "AClassContainingVariousTests",
            cls1,
            new JavaInterface [0]) ;
        JavaField f = new JavaField (
            JavaVisibility.PUBLIC,
            true,
            hashtableClass,
            "aStaticField") ;
        cls3.addClassField (f) ;
        m = new JavaMethod (
            JavaVisibility.PUBLIC,
            model.VOID,
            "aStaticMethod",
            new JavaMethodBody (new Statement [] {
                new Assignment (
                    new FieldReference (field24),
                    new DoubleNumber (3.7))
            })) ;
        cls3.addClassMethod (m) ;
        f = new JavaField (
            JavaVisibility.DEFAULT,
            stringClass,
            "aDefaultVisibleField") ;
        cls3.addField (f) ;
        f = new JavaField (
            JavaVisibility.PUBLIC,
            true,
            stringClass,
            "aFinalField") ;
        cls3.addField (f) ;
        f = new JavaField (
            JavaVisibility.PROTECTED,
            model.getArrayType (stringClass),
            "anArrayField",
            new ArrayContents (new Expression [] {
                    new StringLiteral ("hello"),
                    new StringLiteral ("array")
            })) ;
        cls3.addField (f) ;
        con = new JavaConstructor (
                JavaVisibility.PUBLIC,
                cls3,
                new JavaMethodBody (new ThisConstructorCall ())) ;
            cls3.addConstructor (con) ;
        con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls3,
            new JavaMethodBody (new SuperConstructorCall ())) ;
        cls3.addConstructor (con) ;
        con = new JavaConstructor (
                JavaVisibility.PUBLIC,
                cls3,
                new JavaVariable [] {
                    var = new JavaVariable (model.INT, "i")
                },
                new JavaMethodBody (
                    new ThisConstructorCall (
                        new Expression [] { new VariableReference (var) }))) ;
            cls3.addConstructor (con) ;
        con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls3,
            new JavaVariable [] {
                var = new JavaVariable (model.INT, "i")
            },
            new JavaMethodBody (
                new SuperConstructorCall (
                    new Expression [] { new VariableReference (var) }))) ;
        cls3.addConstructor (con) ;
        JavaVariable var2 ;
        con = new JavaConstructor (
                JavaVisibility.PUBLIC,
                cls3,
                new JavaVariable [] {
                    var = new JavaVariable (model.INT, "i"),
                    var2 = new JavaVariable (model.INT, "j")
                },
                new JavaMethodBody (
                    new ThisConstructorCall (
                        new Expression [] {
                            new VariableReference (var),
                            new VariableReference (var2)
                        }))) ;
            cls3.addConstructor (con) ;
        con = new JavaConstructor (
            JavaVisibility.PUBLIC,
            cls3,
            new JavaVariable [] {
                var = new JavaVariable (model.INT, "i"),
                var2 = new JavaVariable (model.INT, "j")
            },
            new JavaMethodBody (
                new SuperConstructorCall (
                    new Expression [] {
                        new VariableReference (var),
                        new VariableReference (var2)
                    }))) ;
        cls3.addConstructor (con) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            model.VOID,
            "aDefaultVisibleMethod",
            new JavaMethodBody ()) ;
        cls3.addMethod (m) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            stringClass,
            "arrays",
            new JavaMethodBody (new Statement [] {
                    new VariableDeclaration (
                        model.getArrayType (model.getArrayType (stringClass)),
                        "a1",
                        new ArrayConstructorCall (stringClass, new IntegerNumber (15))),
                    new VariableDeclaration (
                        model.getArrayType (stringClass),
                        "a2",
                        new ArrayConstructorCall (
                            stringClass,
                            new ArrayContents (new Expression [] {
                                    new StringLiteral ("hello"),
                                    new StringLiteral ("world")
                            }))),
                    new ReturnStatement (
                        new ArrayElementSelection (
                            new FieldReference (cls3.getField ("anArrayField")),
                            new IntegerNumber (1)))
            })) ;
        cls3.addMethod (m) ;
        JavaClass nullPointerExceptionClass =
            (JavaClass)model.getType ("java.lang.NullPointerException") ; 
        JavaClass illegalArgumentExceptionClass =
            (JavaClass)model.getType (IllegalArgumentException.class) ;
        JavaClass cls ;
        JavaClass types = (JavaClass)model.getType (java.sql.Types.class) ;
        body = new JavaMethodBody (new Statement [] {
            new IfElseStatement (
                new EqualExpression (new IntegerNumber (1), new IntegerNumber (2)),
                new MethodCall (
                    new FieldReference (
                        new JavaClassReference (
                            cls = (JavaClass)model.getType (System.class)),
                        (f = cls.getClassField ("out"))),
                    ((JavaClass)f.getType()).getMethod ("println", new JavaType [] {
                        stringClass
                    }),
                    new Expression [] { new StringLiteral ("hi!") })),
            new IfElseStatement (
                new MethodCall (
                    new StringLiteral ("hello world"),
                    stringClass.getMethod ("startsWith", new JavaType [] {
                        stringClass
                    }),
                    new Expression [] { new StringLiteral ("hello") }),
                 new StringLiteral ("yes."),
                 new StringLiteral ("no.")),
            new SwitchStatement (
                new FieldReference (field22),
                new Expression [] {
                    new FieldReference (
                        new JavaClassReference (types),
                        types.getClassField ("VARCHAR")),
                    new FieldReference (
                        new JavaClassReference (types),
                        types.getClassField ("INTEGER"))
                },
                new Statement [] {
                    new CompoundStatement (new Statement [] {
                        new Assignment (
                            new FieldReference (field24),
                            new StringLiteral ("VARCHAR")),
                        new BreakStatement ()
                    }),
                    new Assignment (
                        new FieldReference (field24),
                        new StringLiteral ("INTEGER"))
                },
                new ReturnStatement ()
        )}) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "conditionals",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new IfElseStatement (
                new EqualExpression (new IntegerNumber (1), new IntegerNumber (2)),
                new ThrowStatement (new ConstructorCall (nullPointerExceptionClass))
            ),
            new WhileLoop (
                new LessThanExpression (
                    new FloatNumber ((float)3.8),
                    new DoubleNumber (7.2)),
                new ThrowStatement (
                    new ConstructorCall (
                        illegalArgumentExceptionClass,
                        new Expression [] { new StringLiteral ("putt") }))
            ),
            new DoLoop (
                new NotEqualExpression (
                    new FieldReference (field21),
                    new StringLiteral ("whoo!")),
                new BreakStatement ()
            ),
            new ForLoop (
                (varDecl = new VariableDeclaration (
                    model.INT,
                    "i",
                    new IntegerNumber (0))),
                new LessThanExpression (
                    new VariableReference (varDecl.getVariable ()),
                    new ByteNumber ((byte)4)),
                new IncrementAfterExpression (
                    new VariableReference (varDecl.getVariable ())),
                new ContinueStatement ()
            )
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "loops",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new ConditionalExpression (
                new True (), new True (), new False ())) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "conditional",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new VariableDeclaration (
                var = new JavaVariable (cls3, "self"),
                new ConstructorCall (cls3)),
            new IfElseStatement (
                new InstanceofExpression (
                    new VariableReference (var),
                    new JavaClassReference (cls3)),
                new Assignment (
                    new VariableReference (var),
                    new TypeCastExpression (cls3, new VariableReference (var)))),
            cls3.getClassFieldReference ()
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "rtti",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new LabelledStatement (
                "l",
                new WhileLoop (
                    new True (),
                    new IfElseStatement (
                        new False (),
                        new ContinueStatement ("l"),
                        new BreakStatement ("m")))),
                new LabelledStatement ("m", new ReturnStatement ())//,
            //new Goto ("l")
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "labels",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new ThrowStatement (new ConstructorCall (nullPointerExceptionClass))
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "oneExceptionThrower",
            new JavaVariable [0],
            new AbstractJavaClass [] { nullPointerExceptionClass },
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new IfElseStatement (
                new EqualExpression (new IntegerNumber (1), new IntegerNumber (2)),
                new ThrowStatement (new ConstructorCall (nullPointerExceptionClass))
            ),
            new WhileLoop (
                new LessThanExpression (
                    new FloatNumber ((float)3.8),
                    new DoubleNumber (7.2)),
                new ThrowStatement (
                    new ConstructorCall (
                        illegalArgumentExceptionClass,
                        new Expression [] { new StringLiteral ("putt") }))
            ),
            new DoLoop (
                new NotEqualExpression (
                    new FieldReference (field21),
                    new StringLiteral ("whoo!")),
                new BreakStatement ()
            ),
            new ForLoop (
                new VariableDeclaration (model.BOOLEAN, "b"),
                new GreaterThanExpression (
                    new MethodCall (method23),
                    new ByteNumber ((byte)4)),
                new ThisConstructorCall (),
                new ContinueStatement ()
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [0],
                new CompoundStatement [0],
                null
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [] {
                    new JavaVariable (nullPointerExceptionClass, "exc"),
                    new JavaVariable (illegalArgumentExceptionClass, "exc")
                },
                new CompoundStatement [] {
                    new CompoundStatement (new Statement [] {
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)) }),
                    new CompoundStatement (new Statement [] {
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)) })
                },
                null
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [0],
                new CompoundStatement [0],
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                })
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [] {
                    new JavaVariable (nullPointerExceptionClass, "exc"),
                    new JavaVariable (illegalArgumentExceptionClass, "exc")
                },
                new CompoundStatement [] {
                    new CompoundStatement (
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass))),
                    new CompoundStatement (
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)))
                },
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (
                            nullPointerExceptionClass,
                            new Expression [] {
                                new StringLiteral ("error: "),
                                new ConstructorCall (nullPointerExceptionClass)
                            }))
                })
            )
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "twoExceptionsThrower",
            new JavaVariable [0],
            new AbstractJavaClass [] {
                nullPointerExceptionClass,
                illegalArgumentExceptionClass
            },
            body) ;
        cls3.addMethod (m) ;
        body = new JavaMethodBody (new Statement [] {
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [0],
                new CompoundStatement [0],
                null
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [] {
                    new JavaVariable (nullPointerExceptionClass, "exc"),
                },
                new CompoundStatement [] {
                    new CompoundStatement (new Statement [] {
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)) }),
                },
                null
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [] {
                    new JavaVariable (nullPointerExceptionClass, "exc"),
                    new JavaVariable (illegalArgumentExceptionClass, "exc")
                },
                new CompoundStatement [] {
                    new CompoundStatement (new Statement [] {
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)) }),
                    new CompoundStatement (new Statement [] {
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)) })
                },
                null
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [0],
                new CompoundStatement [0],
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                })
            ),
            new TryCatchBlock (
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (nullPointerExceptionClass))
                }),
                new JavaVariable [] {
                    new JavaVariable (nullPointerExceptionClass, "exc"),
                    new JavaVariable (illegalArgumentExceptionClass, "exc")
                },
                new CompoundStatement [] {
                    new CompoundStatement (
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass))),
                    new CompoundStatement (
                        new ThrowStatement (
                            new ConstructorCall (nullPointerExceptionClass)))
                },
                new CompoundStatement (new Statement [] {
                    new ThrowStatement (
                        new ConstructorCall (
                            nullPointerExceptionClass,
                            new Expression [] {
                                new StringLiteral ("error: "),
                                new ConstructorCall (nullPointerExceptionClass)
                            }))
                })
            )
        }) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            model.VOID,
            "tryCatchConstructs",
            new JavaVariable [0],
            body) ;
        cls3.addMethod (m) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "tryAddingRemovingExceptions",
            new JavaVariable [0],
            new AbstractJavaClass [] {
                (AbstractJavaClass)model.getType ("java.lang.Error"),
                (AbstractJavaClass)model.getType ("NullPointerException"),
                (AbstractJavaClass)model.getType ("java.rmi.RemoteException")
            },
            new JavaMethodBody ()) ;
        cls3.addMethod (m) ;
        m.removeException ((AbstractJavaClass)model.getType ("java.lang.NullPointerException")) ;
        m.addException ((AbstractJavaClass)model.getType ("java.lang.Exception")) ;
        m.removeException ((AbstractJavaClass)model.getType ("java.lang.Exception")) ;
        m.addException ((AbstractJavaClass)model.getType ("java.lang.ClassCastException")) ;
        JavaClass objectClass = (JavaClass)model.getType (Object.class) ;
        m = new JavaMethod (
            JavaVisibility.PUBLIC,
            objectClass,
            "clone",
            new JavaMethodBody (
                new ReturnStatement (
                    new MethodCall (
                        SuperReference.getInstance (),
                        objectClass.getMethod ("clone"))))) ;
        cls3.addMethod (m) ;
        m = new JavaMethod (
            JavaVisibility.DEFAULT,
            false,
            model.VOID,
            "classFields",
            new JavaVariable [0],
            new AbstractJavaClass [0],
            new JavaMethodBody (new Statement [] {
                    model.INT.getClassFieldReference (),
                    model.DOUBLE.getClassFieldReference (),
                    model.VOID.getClassFieldReference (),
                    cls3.getClassFieldReference ()
            })) ;
        cls3.addMethod (m) ;

        JavaClass cls4 = new JavaClass (
            model,
            pkg,
            true,
            JavaVisibility.PUBLIC,
            "AFinalClass") ;

        JavaClass cls5 = new JavaClass (
            model,
            pkg,
            true,
            JavaVisibility.PUBLIC,
            "InnerClasses") ;
        cls5.addClass (new JavaClass (model, null, JavaVisibility.PRIVATE, "InnerClass1")) ;
        new JavaClass (cls5, JavaVisibility.PUBLIC, "InnerClass2") ;
        cls5.addClassClass (new JavaClass (model, null, JavaVisibility.PRIVATE, "InnerClass3")) ;

        System.out.println ("Model:") ;
        Writer w = new OutputStreamWriter (System.out) ;
        intf1.writeSourceCodeOn (w) ;
        System.out.println ("\n--------------------------------" ) ;
        cls1.writeSourceCodeOn (w) ;
        System.out.println ("\n--------------------------------") ;
        cls2.writeSourceCodeOn (w) ;
        System.out.println ("\n--------------------------------") ;
        cls3.writeSourceCodeOn (w) ;
        System.out.println ("\n--------------------------------") ;
        cls3.writeSourceCodeOn (w) ;
        System.out.println ("\n--------------------------------") ;
        cls5.writeSourceCodeOn (w) ;

    }// constructor

}// class Test