1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 package com.sun.org.apache.bcel.internal.generic;
   6 
   7 /* ====================================================================
   8  * The Apache Software License, Version 1.1
   9  *
  10  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  11  * reserved.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  *
  17  * 1. Redistributions of source code must retain the above copyright
  18  *    notice, this list of conditions and the following disclaimer.
  19  *
  20  * 2. Redistributions in binary form must reproduce the above copyright
  21  *    notice, this list of conditions and the following disclaimer in
  22  *    the documentation and/or other materials provided with the
  23  *    distribution.
  24  *
  25  * 3. The end-user documentation included with the redistribution,
  26  *    if any, must include the following acknowledgment:
  27  *       "This product includes software developed by the
  28  *        Apache Software Foundation (http://www.apache.org/)."
  29  *    Alternately, this acknowledgment may appear in the software itself,
  30  *    if and wherever such third-party acknowledgments normally appear.
  31  *
  32  * 4. The names "Apache" and "Apache Software Foundation" and
  33  *    "Apache BCEL" must not be used to endorse or promote products
  34  *    derived from this software without prior written permission. For
  35  *    written permission, please contact apache@apache.org.
  36  *
  37  * 5. Products derived from this software may not be called "Apache",
  38  *    "Apache BCEL", nor may "Apache" appear in their name, without
  39  *    prior written permission of the Apache Software Foundation.
  40  *
  41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  44  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  52  * SUCH DAMAGE.
  53  * ====================================================================
  54  *
  55  * This software consists of voluntary contributions made by many
  56  * individuals on behalf of the Apache Software Foundation.  For more
  57  * information on the Apache Software Foundation, please see
  58  * <http://www.apache.org/>.
  59  */
  60 
  61 import com.sun.org.apache.bcel.internal.Constants;
  62 import com.sun.org.apache.bcel.internal.classfile.*;
  63 import java.util.ArrayList;
  64 import java.util.Iterator;
  65 
  66 /**
  67  * Template class for building up a java class. May be initialized with an
  68  * existing java class (file).
  69  *
  70  * @see JavaClass
  71  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  72  */
  73 public class ClassGen extends AccessFlags implements Cloneable {
  74   /* Corresponds to the fields found in a JavaClass object.
  75    */
  76   private String   class_name, super_class_name, file_name;
  77   private int      class_name_index = -1, superclass_name_index = -1;
  78   private int      major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1;
  79 
  80   private ConstantPoolGen cp; // Template for building up constant pool
  81 
  82   // ArrayLists instead of arrays to gather fields, methods, etc.
  83   private ArrayList   field_vec     = new ArrayList();
  84   private ArrayList   method_vec    = new ArrayList();
  85   private ArrayList   attribute_vec = new ArrayList();
  86   private ArrayList   interface_vec = new ArrayList();
  87 
  88   /** Convenience constructor to set up some important values initially.
  89    *
  90    * @param class_name fully qualified class name
  91    * @param super_class_name fully qualified superclass name
  92    * @param file_name source file name
  93    * @param access_flags access qualifiers
  94    * @param interfaces implemented interfaces
  95    * @param cp constant pool to use
  96    */
  97   public ClassGen(String class_name, String super_class_name, String file_name,
  98                   int access_flags, String[] interfaces, ConstantPoolGen cp) {
  99     this.class_name       = class_name;
 100     this.super_class_name = super_class_name;
 101     this.file_name        = file_name;
 102     this.access_flags     = access_flags;
 103     this.cp               = cp;
 104 
 105     // Put everything needed by default into the constant pool and the vectors
 106     if(file_name != null)
 107       addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2,
 108                                   cp.addUtf8(file_name), cp.getConstantPool()));
 109 
 110     class_name_index      = cp.addClass(class_name);
 111     superclass_name_index = cp.addClass(super_class_name);
 112 
 113     if(interfaces != null)
 114       for(int i=0; i < interfaces.length; i++)
 115         addInterface(interfaces[i]);
 116   }
 117 
 118   /** Convenience constructor to set up some important values initially.
 119    *
 120    * @param class_name fully qualified class name
 121    * @param super_class_name fully qualified superclass name
 122    * @param file_name source file name
 123    * @param access_flags access qualifiers
 124    * @param interfaces implemented interfaces
 125    */
 126   public ClassGen(String class_name, String super_class_name, String file_name,
 127                   int access_flags, String[] interfaces) {
 128     this(class_name, super_class_name, file_name, access_flags, interfaces,
 129          new ConstantPoolGen());
 130   }
 131 
 132   /**
 133    * Initialize with existing class.
 134    * @param clazz JavaClass object (e.g. read from file)
 135    */
 136   public ClassGen(JavaClass clazz) {
 137     class_name_index      = clazz.getClassNameIndex();
 138     superclass_name_index = clazz.getSuperclassNameIndex();
 139     class_name            = clazz.getClassName();
 140     super_class_name      = clazz.getSuperclassName();
 141     file_name             = clazz.getSourceFileName();
 142     access_flags          = clazz.getAccessFlags();
 143     cp                    = new ConstantPoolGen(clazz.getConstantPool());
 144     major                 = clazz.getMajor();
 145     minor                 = clazz.getMinor();
 146 
 147     Attribute[] attributes = clazz.getAttributes();
 148     Method[]    methods    = clazz.getMethods();
 149     Field[]     fields     = clazz.getFields();
 150     String[]    interfaces = clazz.getInterfaceNames();
 151 
 152     for(int i=0; i < interfaces.length; i++)
 153       addInterface(interfaces[i]);
 154 
 155     for(int i=0; i < attributes.length; i++)
 156       addAttribute(attributes[i]);
 157 
 158     for(int i=0; i < methods.length; i++)
 159       addMethod(methods[i]);
 160 
 161     for(int i=0; i < fields.length; i++)
 162       addField(fields[i]);
 163   }
 164 
 165   /**
 166    * @return the (finally) built up Java class object.
 167    */
 168   public JavaClass getJavaClass() {
 169     int[]        interfaces = getInterfaces();
 170     Field[]      fields     = getFields();
 171     Method[]     methods    = getMethods();
 172     Attribute[]  attributes = getAttributes();
 173 
 174     // Must be last since the above calls may still add something to it
 175     ConstantPool cp         = this.cp.getFinalConstantPool();
 176 
 177     return new JavaClass(class_name_index, superclass_name_index,
 178                          file_name, major, minor, access_flags,
 179                          cp, interfaces, fields, methods, attributes);
 180   }
 181 
 182   /**
 183    * Add an interface to this class, i.e., this class has to implement it.
 184    * @param name interface to implement (fully qualified class name)
 185    */
 186   public void addInterface(String name) {
 187     interface_vec.add(name);
 188   }
 189 
 190   /**
 191    * Remove an interface from this class.
 192    * @param name interface to remove (fully qualified name)
 193    */
 194   public void removeInterface(String name) {
 195     interface_vec.remove(name);
 196   }
 197 
 198   /**
 199    * @return major version number of class file
 200    */
 201   public int  getMajor()      { return major; }
 202 
 203   /** Set major version number of class file, default value is 45 (JDK 1.1)
 204    * @param major major version number
 205    */
 206   public void setMajor(int major) {
 207     this.major = major;
 208   }
 209 
 210   /** Set minor version number of class file, default value is 3 (JDK 1.1)
 211    * @param minor minor version number
 212    */
 213   public void setMinor(int minor) {
 214     this.minor = minor;
 215   }
 216 
 217   /**
 218    * @return minor version number of class file
 219    */
 220   public int  getMinor()      { return minor; }
 221 
 222   /**
 223    * Add an attribute to this class.
 224    * @param a attribute to add
 225    */
 226   public void addAttribute(Attribute a)    { attribute_vec.add(a); }
 227 
 228   /**
 229    * Add a method to this class.
 230    * @param m method to add
 231    */
 232   public void addMethod(Method m)          { method_vec.add(m); }
 233 
 234   /**
 235    * Convenience method.
 236    *
 237    * Add an empty constructor to this class that does nothing but calling super().
 238    * @param access rights for constructor
 239    */
 240   public void addEmptyConstructor(int access_flags) {
 241     InstructionList il = new InstructionList();
 242     il.append(InstructionConstants.THIS); // Push `this'
 243     il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name,
 244                                                 "<init>", "()V")));
 245     il.append(InstructionConstants.RETURN);
 246 
 247     MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null,
 248                        "<init>", class_name, il, cp);
 249     mg.setMaxStack(1);
 250     addMethod(mg.getMethod());
 251   }
 252 
 253   /**
 254    * Add a field to this class.
 255    * @param f field to add
 256    */
 257   public void addField(Field f)            { field_vec.add(f); }
 258 
 259   public boolean containsField(Field f)    { return field_vec.contains(f); }
 260 
 261   /** @return field object with given name, or null
 262    */
 263   public Field containsField(String name) {
 264     for(Iterator e=field_vec.iterator(); e.hasNext(); ) {
 265       Field f = (Field)e.next();
 266       if(f.getName().equals(name))
 267         return f;
 268     }
 269 
 270     return null;
 271   }
 272 
 273   /** @return method object with given name and signature, or null
 274    */
 275   public Method containsMethod(String name, String signature) {
 276     for(Iterator e=method_vec.iterator(); e.hasNext();) {
 277       Method m = (Method)e.next();
 278       if(m.getName().equals(name) && m.getSignature().equals(signature))
 279         return m;
 280     }
 281 
 282     return null;
 283   }
 284 
 285   /**
 286    * Remove an attribute from this class.
 287    * @param a attribute to remove
 288    */
 289   public void removeAttribute(Attribute a) { attribute_vec.remove(a); }
 290 
 291   /**
 292    * Remove a method from this class.
 293    * @param m method to remove
 294    */
 295   public void removeMethod(Method m)       { method_vec.remove(m); }
 296 
 297   /** Replace given method with new one. If the old one does not exist
 298    * add the new_ method to the class anyway.
 299    */
 300   public void replaceMethod(Method old, Method new_) {
 301     if(new_ == null)
 302       throw new ClassGenException("Replacement method must not be null");
 303 
 304     int i = method_vec.indexOf(old);
 305 
 306     if(i < 0)
 307       method_vec.add(new_);
 308     else
 309       method_vec.set(i, new_);
 310   }
 311 
 312   /** Replace given field with new one. If the old one does not exist
 313    * add the new_ field to the class anyway.
 314    */
 315   public void replaceField(Field old, Field new_) {
 316     if(new_ == null)
 317       throw new ClassGenException("Replacement method must not be null");
 318 
 319     int i = field_vec.indexOf(old);
 320 
 321     if(i < 0)
 322       field_vec.add(new_);
 323     else
 324       field_vec.set(i, new_);
 325   }
 326 
 327   /**
 328    * Remove a field to this class.
 329    * @param f field to remove
 330    */
 331   public void removeField(Field f)         { field_vec.remove(f); }
 332 
 333   public String getClassName()      { return class_name; }
 334   public String getSuperclassName() { return super_class_name; }
 335   public String getFileName()       { return file_name; }
 336 
 337   public void setClassName(String name) {
 338     class_name = name.replace('/', '.');
 339     class_name_index = cp.addClass(name);
 340   }
 341 
 342   public void setSuperclassName(String name) {
 343     super_class_name = name.replace('/', '.');
 344     superclass_name_index = cp.addClass(name);
 345   }
 346 
 347   public Method[] getMethods() {
 348     Method[] methods = new Method[method_vec.size()];
 349     method_vec.toArray(methods);
 350     return methods;
 351   }
 352 
 353   public void setMethods(Method[] methods) {
 354     method_vec.clear();
 355     for(int m=0; m<methods.length; m++)
 356       addMethod(methods[m]);
 357   }
 358 
 359   public void setMethodAt(Method method, int pos) {
 360     method_vec.set(pos, method);
 361   }
 362 
 363   public Method getMethodAt(int pos) {
 364     return (Method)method_vec.get(pos);
 365   }
 366 
 367   public String[] getInterfaceNames() {
 368     int      size = interface_vec.size();
 369     String[] interfaces = new String[size];
 370 
 371     interface_vec.toArray(interfaces);
 372     return interfaces;
 373   }
 374 
 375   public int[] getInterfaces() {
 376     int   size = interface_vec.size();
 377     int[] interfaces = new int[size];
 378 
 379     for(int i=0; i < size; i++)
 380       interfaces[i] = cp.addClass((String)interface_vec.get(i));
 381 
 382     return interfaces;
 383   }
 384 
 385   public Field[] getFields() {
 386     Field[] fields = new Field[field_vec.size()];
 387     field_vec.toArray(fields);
 388     return fields;
 389   }
 390 
 391   public Attribute[] getAttributes() {
 392     Attribute[] attributes = new Attribute[attribute_vec.size()];
 393     attribute_vec.toArray(attributes);
 394     return attributes;
 395   }
 396 
 397   public ConstantPoolGen getConstantPool() { return cp; }
 398   public void setConstantPool(ConstantPoolGen constant_pool) {
 399     cp = constant_pool;
 400   }
 401 
 402   public void setClassNameIndex(int class_name_index) {
 403     this.class_name_index = class_name_index;
 404     class_name = cp.getConstantPool().
 405       getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
 406   }
 407 
 408   public void setSuperclassNameIndex(int superclass_name_index) {
 409     this.superclass_name_index = superclass_name_index;
 410     super_class_name = cp.getConstantPool().
 411       getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
 412   }
 413 
 414   public int getSuperclassNameIndex() { return superclass_name_index; }
 415 
 416   public int getClassNameIndex()   { return class_name_index; }
 417 
 418   private ArrayList observers;
 419 
 420   /** Add observer for this object.
 421    */
 422   public void addObserver(ClassObserver o) {
 423     if(observers == null)
 424       observers = new ArrayList();
 425 
 426     observers.add(o);
 427   }
 428 
 429   /** Remove observer for this object.
 430    */
 431   public void removeObserver(ClassObserver o) {
 432     if(observers != null)
 433       observers.remove(o);
 434   }
 435 
 436   /** Call notify() method on all observers. This method is not called
 437    * automatically whenever the state has changed, but has to be
 438    * called by the user after he has finished editing the object.
 439    */
 440   public void update() {
 441     if(observers != null)
 442       for(Iterator e = observers.iterator(); e.hasNext(); )
 443         ((ClassObserver)e.next()).notify(this);
 444   }
 445 
 446   public Object clone() {
 447     try {
 448       return super.clone();
 449     } catch(CloneNotSupportedException e) {
 450       System.err.println(e);
 451       return null;
 452     }
 453   }
 454 }