import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* Provides a <em>builder</em> class to construct Jak source classes.
* A <code>ClassBuilder</code> class can be used to build multiple classes
* by either re-using state information for multiple classes or by invoking
* {@link ClassBuilder#initialize()} between class constructions.
*
* @layer<codegen>
*/
public class ClassBuilder extends CodeBuffer {
/**
* Clears the state information about the current class being
* constructed so that a new class can be built.
*
* @layer<codegen>
*/
public CodeBuffer clear() {
layerName = null ;
className = null ;
superName = null ;
imports.clear () ;
interfaces.clear() ;
methods.clear() ;
modifiers.clear() ;
return this ;
}
/**
* Adds a package/class to the imports list for this class.
*
* @layer<codegen>
**/
public ClassBuilder addImport (String name) {
imports.add (name) ;
return this ;
}
/**
* Removes an import from the referenced imports for this class.
*
* @layer<codegen>
*/
public ClassBuilder removeImport( String name ) {
imports.remove( name ) ;
return this ;
}
/**
* Adds an interface to the implemented interfaces for this class.
*
* @layer<codegen>
*/
public ClassBuilder addInterface( String name ) {
interfaces.add( name ) ;
return this ;
}
/**
* Removes an interface from the implemented interfaces for this class.
*
* @layer<codegen>
*/
public ClassBuilder removeInterface( String name ) {
interfaces.remove( name ) ;
return this ;
}
/**
* Adds a method to the class by extracting it from the contents of
* a given {@link MethodBuilder} instance.
*
* @layer<codegen>
*/
public ClassBuilder addMethod( MethodBuilder method ) {
addMethod( method.getSignature(), method.toString() ) ;
return this ;
}
/**
* Adds a method signature and body to be included in the generated
* class.
*
* @layer<codegen>
*/
public ClassBuilder addMethod( String signature, String method ) {
methods.put( signature, method ) ;
return this ;
}
/**
* Removes a method from the generated class.
*
* @layer<codegen>
*/
public ClassBuilder removeMethod( String signature ) {
methods.remove( signature ) ;
return this ;
}
/**
* Adds a class modifier to the class to be generated.
*
* @layer<codegen>
*/
public ClassBuilder addModifier( Modifier modifier ) {
if ( modifier == null )
throw new IllegalArgumentException( "\"modifier\" is null" ) ;
if ( modifier.equals( Modifier.REFINES ) && superName != null )
throw new IllegalArgumentException( "invalid w/ super class" ) ;
modifiers.add( modifier ) ;
return this ;
}
/**
* Removes a class modifier from the class.
*
* @layer<codegen>
*/
public ClassBuilder removeModifier( Modifier modifier ) {
modifiers.remove( modifier ) ;
return this ;
}
/**
* Sets the layer name, if <code>name</code> is non-null, or clears
* the layer name if <code>name==null</code>.
*
* @layer<codegen>
*/
public ClassBuilder setLayerName( String name ) {
layerName = name ;
return this ;
}
/**
* Sets the class name, if <code>name</code> is non-null, or clears the
* class name if <code>name==null</code>.
*
* @layer<codegen>
*/
public ClassBuilder setClassName( String name ) {
className = name ;
return this ;
}
/**
* Sets the super class name, if <code>name</code> is non-null, or
* clears the super class if <code>name==null</code>. Note: assigning
* a super class is incompatible with the {@link Modifier#REFINES}
* modifier.
*
* @layer<codegen>
*/
public ClassBuilder setSuperName( String name ) {
if ( modifiers.contains( Modifier.REFINES ) && name != null )
throw new IllegalArgumentException( "invalid w/ REFINES" ) ;
superName = name ;
return this ;
}
/**
* Returns a {@link String} containing the generated code for the
* currently defined class, complete with line separators.
*
* @layer<codegen>
*/
public String toString() {
CodeBuffer buffer = new CodeBuffer() ;
if ( layerName != null && layerName.length() > 0 ) {
buffer.append( Keyword.LAYER ) ;
buffer.append( layerName ) ;
buffer.append( ';' ) ;
buffer.endLine().endLine() ;
}
if (imports.size () > 0) {
for (Iterator p = imports.iterator () ; p.hasNext () ; ) {
buffer.append (Keyword.IMPORT) ;
buffer.append ((String) p.next ()) ;
buffer.append( ';' ) ;
buffer.endLine() ;
}
buffer.endLine() ;
}
for ( Iterator p = modifiers.iterator() ; p.hasNext() ; )
buffer.append( ( Modifier ) p.next() ) ;
buffer.append( Keyword.CLASS ) ;
buffer.append( className ) ;
if ( superName != null ) {
Object[] phrase = new Object[] {Keyword.EXTENDS, superName} ;
buffer.append( Arrays.asList( phrase ) ) ;
}
if ( interfaces.size() > 0 ) {
List phrase = new ArrayList( interfaces ) ;
Collections.sort( phrase ) ;
ListIterator p = phrase.listIterator( phrase.size() - 1 ) ;
while ( p.hasPrevious() )
p.set( ( ( String ) p.previous() ) + ',' ) ;
phrase.add( 0, Keyword.IMPLEMENTS ) ;
buffer.append( phrase ) ;
}
buffer.append( "{" ).endLine() ;
buffer.indent() ;
// Insert any lines built by direct calls to "append", etc.:
//
String header = super.toString().trim() ;
if ( header != null && header.length() > 0 ) {
buffer.endLine() ;
buffer.appendLines( header ) ;
buffer.endLine() ;
}
for ( Iterator p = methods.values().iterator() ; p.hasNext() ; ) {
buffer.endLine() ;
buffer.appendLines( p.next().toString() ) ;
buffer.endLine() ;
}
buffer.outdent() ;
buffer.endLine().append( "}" ) ;
return buffer.toString() ;
}
//-------------------------------------------------------------------//
// Private state information:
//-------------------------------------------------------------------//
private String layerName = null ;
private String className = null ;
private String superName = null ;
final private Set imports = new TreeSet() ;
final private Set interfaces = new TreeSet() ;
final private Map methods = new TreeMap() ;
final private Set modifiers = new TreeSet() ;
}