001    /*
002    @license.text@
003     */
004    package biz.hammurapi.codegen;
005    
006    import java.util.ArrayList;
007    import java.util.Collection;
008    import java.util.HashSet;
009    import java.util.Iterator;
010    import java.util.Properties;
011    import java.util.Set;
012    
013    import org.apache.bcel.Constants;
014    import org.apache.bcel.classfile.Utility;
015    import org.apache.bcel.generic.ClassGen;
016    import org.apache.bcel.generic.InstructionList;
017    import org.apache.bcel.generic.MethodGen;
018    import org.apache.bcel.generic.Type;
019    
020    import biz.hammurapi.codegen.JavaTokenTypes;
021    
022    import antlr.collections.AST;
023    import biz.hammurapi.util.Parameter;
024    
025    
026    /**
027     * @author Pavel Vlasov
028     * @version $Revision: 1.7 $
029     */
030    public class Interface extends ClassGeneratorBase {
031    
032            /**
033             * Constructor
034             * @param definition E.g. <CODE>public interface C extends a.b.A, a.b.c.d.B</CODE> Superinterfaces names shall be fully qualified.
035             * @param description
036             * @param listener
037             * @throws GenerationException
038             */
039            public Interface(String definition, String description, GenerationListener listener) throws GenerationException {
040                    this.listener=listener;         
041                    AST ast=typeDefinition(definition);
042                    if (ast==null) {
043                        throw new GenerationException("Cannot parse definition: "+definition);
044                    }
045                    
046                    if (ast.getType()==JavaTokenTypes.INTERFACE_DEF) {
047                            Set modifiers=new HashSet();
048                            String name=null;
049                            Collection superInterfaces=new ArrayList();
050                            for (AST node=ast.getFirstChild(); node!=null; node=node.getNextSibling()) {
051                                    switch (node.getType()) {
052                                            case JavaTokenTypes.MODIFIERS:
053                                                    for (AST child=node.getFirstChild(); child!=null; child=child.getNextSibling()) {
054                                                            modifiers.add(child.getText());
055                                                    }
056                                                    break;
057                                            case JavaTokenTypes.IDENT:
058                                                    name=node.getText();
059                                                    break;
060                                            case JavaTokenTypes.DOT:
061                                                    name=toString(node);
062                                                    break;
063                                            case JavaTokenTypes.EXTENDS_CLAUSE:
064                                                    for (AST interfaceNode=node.getFirstChild(); interfaceNode!=null; interfaceNode=interfaceNode.getNextSibling()) {
065                                                            superInterfaces.add(toString(interfaceNode));
066                                                    }
067                                                    break;
068                                            default:
069                                                    throw new GenerationException("Unexpected node: "+node);                                                                                                
070                                    }
071                            }                       
072                                                    
073                            cg = new ClassGen(
074                                            name,
075                                            "java.lang.Object",
076                                            description==null ? "<generated>" : description,
077                                            modifiers(modifiers) | Constants.ACC_INTERFACE,
078                                            (String[]) superInterfaces.toArray(new String[superInterfaces.size()]));
079                            
080                            if (listener!=null) {
081                                    listener.onClass(cg, description);
082                            }
083                    } else {
084                            throw new GenerationException("Invalid node type "+ast.getType()+" in definition '"+definition+"'");
085                    }
086            }
087                    
088            /**
089             * 
090             * @param definition E.g. <CODE>public void setX(int x)</CODE> All types shall be fully qualified.
091             * @param parameters Collection of {@link biz.hammurapi.util.Parameter} Parameters to be appended to parameters in definition. Can be null.
092             * @param description
093             * @return
094             * @throws GenerationException
095             */
096            public MethodGen addMethod(String definition, Collection parameters, String description, Properties attributes) throws GenerationException {
097                    AST ast=field(definition);
098                    if (ast.getType()==JavaTokenTypes.METHOD_DEF) {
099                            Set modifiers=new HashSet();
100                            String name=null;
101                            String returnType=null;
102                            Collection throwsList=new ArrayList();
103                            Collection allParameters=new ArrayList();
104                            class ParameterImpl implements Parameter {
105    
106                                    private String type;
107                                    private String name;
108                                    
109                                    ParameterImpl(String name, String type) {
110                                            this.name=name;
111                                            this.type=type;
112                                    }
113    
114                                    public String getName() {
115                                            return name;
116                                    }
117    
118                                    public String getType() {
119                                            return type;
120                                    }
121                                    
122                            }
123                            
124                            for (AST node=ast.getFirstChild(); node!=null; node=node.getNextSibling()) {
125                                    switch (node.getType()) {
126                                            case JavaTokenTypes.MODIFIERS:
127                                                    for (AST child=node.getFirstChild(); child!=null; child=child.getNextSibling()) {
128                                                            modifiers.add(child.getText());
129                                                    }
130                                                    break;
131                                            case JavaTokenTypes.IDENT:
132                                            case JavaTokenTypes.INIT:
133                                                    name=node.getText();
134                                                    break;
135                                            case JavaTokenTypes.TYPE:
136                                                    returnType = toString(node.getFirstChild());
137                                                    break;
138                                            case JavaTokenTypes.PARAMETERS:
139                                                    for (AST pnode = node.getFirstChild(); pnode!=null; pnode=pnode.getNextSibling()) {
140                                                            for (AST ppnode=pnode.getFirstChild(); ppnode!=null; ppnode=pnode.getNextSibling()) {
141                                                                    String pname=null;
142                                                                    String ptype=null;
143                                                                    switch (ppnode.getType()) {
144                                                                            case JavaTokenTypes.IDENT:
145                                                                                    pname=node.getText();
146                                                                                    break;
147                                                                            case JavaTokenTypes.TYPE:
148                                                                                    ptype=toString(ppnode.getFirstChild());
149                                                                                    break;
150                                                                            default:
151                                                                                    throw new GenerationException("Unexpected node: "+ppnode.getText());
152                                                                    }
153                                                                    allParameters.add(new ParameterImpl(pname, ptype));
154                                                            }
155                                                    }
156                                                    break;
157                                            case JavaTokenTypes.LITERAL_throws:
158                                                    for (AST tnode=node.getFirstChild(); tnode!=null; tnode=tnode.getNextSibling()) {
159                                                            throwsList.add(toString(tnode));
160                                                    }
161                                                    break;
162                                                    
163                                            default:
164                                                    throw new GenerationException("Unexpected node: "+node);                                                                                                
165                                    }
166                            }
167                            
168                            if (parameters!=null) {
169                                    allParameters.addAll(parameters);
170                            }
171                            
172                            Collection signature=new ArrayList();
173                            signature.add(name);
174                            Iterator pit=allParameters.iterator();
175                            while (pit.hasNext()) {
176                                    signature.add(((Parameter) pit.next()).getType());
177                            }
178                            
179                            if (checkMethod(signature, returnType, throwsList)) {
180                                    Type[] args = new Type[allParameters.size()];
181                                    String[] argNames = new String[args.length];
182                                    pit=allParameters.iterator();
183                                    for (int i=0; pit.hasNext(); i++) {
184                                            Parameter p=(Parameter) pit.next();
185                                            args[i]=Type.getType(Utility.getSignature(p.getType()));
186                                            argNames[i]=p.getName();
187                                    }
188                                    
189                                    InstructionList emptyInstructionList = new InstructionList();
190                                    MethodGen mg =
191                                            new MethodGen(
192                                                            Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | modifiers(modifiers),
193                                                            java2BcelType(returnType),
194                                                            args,
195                                                            argNames,
196                                                            name, 
197                                                            cg.getClassName(),
198                                                            emptyInstructionList, 
199                                                            cg.getConstantPool());
200                                                    
201                                    Iterator thit=throwsList.iterator();
202                                    while (thit.hasNext()) {
203                                            mg.addException((String) thit.next());
204                                    }
205                                    
206                                    cg.addMethod(mg.getMethod());
207                    
208                                    emptyInstructionList.dispose();
209                                    
210                                    if (listener!=null && (cg.isPublic() || cg.isProtected())) {
211                                            listener.onMethod(cg.getClassName(), mg.toString(), description, attributes);
212                                    }
213                                    
214                                    return mg;
215                            }
216                            return null;
217                    }
218                    throw new GenerationException("Invalid node type "+ast.getType()+" in definition '"+definition+"'");
219            }
220            
221            /**
222             * Creates a public static final field of specified name and type.
223             * @param name
224             * @param type
225             * @param description
226             * @param attributes
227             * @throws GenerationException
228             */
229            public void addField(String name, String type, String description, Properties attributes) throws GenerationException {
230                    addField("public static final "+type+" "+name, description, attributes);
231            }       
232    }