1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.bcel.internal.generic;
  23 
  24 
  25 import com.sun.org.apache.bcel.internal.Constants;
  26 import com.sun.org.apache.bcel.internal.classfile.*;
  27 import java.util.ArrayList;
  28 import java.util.Iterator;
  29 
  30 /**
  31  * Template class for building up a java class. May be initialized with an
  32  * existing java class (file).
  33  *
  34  * @see JavaClass
  35  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  36  */
  37 public class ClassGen extends AccessFlags implements Cloneable {
  38   /* Corresponds to the fields found in a JavaClass object.
  39    */
  40   private String   class_name, super_class_name, file_name;
  41   private int      class_name_index = -1, superclass_name_index = -1;
  42   private int      major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1;
  43 
  44   private ConstantPoolGen cp; // Template for building up constant pool
  45 
  46   // ArrayLists instead of arrays to gather fields, methods, etc.
  47   private ArrayList   field_vec     = new ArrayList();
  48   private ArrayList   method_vec    = new ArrayList();
  49   private ArrayList   attribute_vec = new ArrayList();
  50   private ArrayList   interface_vec = new ArrayList();
  51 
  52   /** Convenience constructor to set up some important values initially.
  53    *
  54    * @param class_name fully qualified class name
  55    * @param super_class_name fully qualified superclass name
  56    * @param file_name source file name
  57    * @param access_flags access qualifiers
  58    * @param interfaces implemented interfaces
  59    * @param cp constant pool to use
  60    */
  61   public ClassGen(String class_name, String super_class_name, String file_name,
  62                   int access_flags, String[] interfaces, ConstantPoolGen cp) {
  63     this.class_name       = class_name;
  64     this.super_class_name = super_class_name;
  65     this.file_name        = file_name;
  66     this.access_flags     = access_flags;
  67     this.cp               = cp;
  68 
  69     // Put everything needed by default into the constant pool and the vectors
  70     if(file_name != null)
  71       addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2,
  72                                   cp.addUtf8(file_name), cp.getConstantPool()));
  73 
  74     class_name_index      = cp.addClass(class_name);
  75     superclass_name_index = cp.addClass(super_class_name);
  76 
  77     if(interfaces != null)
  78       for(int i=0; i < interfaces.length; i++)
  79         addInterface(interfaces[i]);
  80   }
  81 
  82   /** Convenience constructor to set up some important values initially.
  83    *
  84    * @param class_name fully qualified class name
  85    * @param super_class_name fully qualified superclass name
  86    * @param file_name source file name
  87    * @param access_flags access qualifiers
  88    * @param interfaces implemented interfaces
  89    */
  90   public ClassGen(String class_name, String super_class_name, String file_name,
  91                   int access_flags, String[] interfaces) {
  92     this(class_name, super_class_name, file_name, access_flags, interfaces,
  93          new ConstantPoolGen());
  94   }
  95 
  96   /**
  97    * Initialize with existing class.
  98    * @param clazz JavaClass object (e.g. read from file)
  99    */
 100   public ClassGen(JavaClass clazz) {
 101     class_name_index      = clazz.getClassNameIndex();
 102     superclass_name_index = clazz.getSuperclassNameIndex();
 103     class_name            = clazz.getClassName();
 104     super_class_name      = clazz.getSuperclassName();
 105     file_name             = clazz.getSourceFileName();
 106     access_flags          = clazz.getAccessFlags();
 107     cp                    = new ConstantPoolGen(clazz.getConstantPool());
 108     major                 = clazz.getMajor();
 109     minor                 = clazz.getMinor();
 110 
 111     Attribute[] attributes = clazz.getAttributes();
 112     Method[]    methods    = clazz.getMethods();
 113     Field[]     fields     = clazz.getFields();
 114     String[]    interfaces = clazz.getInterfaceNames();
 115 
 116     for(int i=0; i < interfaces.length; i++)
 117       addInterface(interfaces[i]);
 118 
 119     for(int i=0; i < attributes.length; i++)
 120       addAttribute(attributes[i]);
 121 
 122     for(int i=0; i < methods.length; i++)
 123       addMethod(methods[i]);
 124 
 125     for(int i=0; i < fields.length; i++)
 126       addField(fields[i]);
 127   }
 128 
 129   /**
 130    * @return the (finally) built up Java class object.
 131    */
 132   public JavaClass getJavaClass() {
 133     int[]        interfaces = getInterfaces();
 134     Field[]      fields     = getFields();
 135     Method[]     methods    = getMethods();
 136     Attribute[]  attributes = getAttributes();
 137 
 138     // Must be last since the above calls may still add something to it
 139     ConstantPool cp         = this.cp.getFinalConstantPool();
 140 
 141     return new JavaClass(class_name_index, superclass_name_index,
 142                          file_name, major, minor, access_flags,
 143                          cp, interfaces, fields, methods, attributes);
 144   }
 145 
 146   /**
 147    * Add an interface to this class, i.e., this class has to implement it.
 148    * @param name interface to implement (fully qualified class name)
 149    */
 150   public void addInterface(String name) {
 151     interface_vec.add(name);
 152   }
 153 
 154   /**
 155    * Remove an interface from this class.
 156    * @param name interface to remove (fully qualified name)
 157    */
 158   public void removeInterface(String name) {
 159     interface_vec.remove(name);
 160   }
 161 
 162   /**
 163    * @return major version number of class file
 164    */
 165   public int  getMajor()      { return major; }
 166 
 167   /** Set major version number of class file, default value is 45 (JDK 1.1)
 168    * @param major major version number
 169    */
 170   public void setMajor(int major) {
 171     this.major = major;
 172   }
 173 
 174   /** Set minor version number of class file, default value is 3 (JDK 1.1)
 175    * @param minor minor version number
 176    */
 177   public void setMinor(int minor) {
 178     this.minor = minor;
 179   }
 180 
 181   /**
 182    * @return minor version number of class file
 183    */
 184   public int  getMinor()      { return minor; }
 185 
 186   /**
 187    * Add an attribute to this class.
 188    * @param a attribute to add
 189    */
 190   public void addAttribute(Attribute a)    { attribute_vec.add(a); }
 191 
 192   /**
 193    * Add a method to this class.
 194    * @param m method to add
 195    */
 196   public void addMethod(Method m)          { method_vec.add(m); }
 197 
 198   /**
 199    * Convenience method.
 200    *
 201    * Add an empty constructor to this class that does nothing but calling super().
 202    * @param access rights for constructor
 203    */
 204   public void addEmptyConstructor(int access_flags) {
 205     InstructionList il = new InstructionList();
 206     il.append(InstructionConstants.THIS); // Push `this'
 207     il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name,
 208                                                 "<init>", "()V")));
 209     il.append(InstructionConstants.RETURN);
 210 
 211     MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null,
 212                        "<init>", class_name, il, cp);
 213     mg.setMaxStack(1);
 214     addMethod(mg.getMethod());
 215   }
 216 
 217   /**
 218    * Add a field to this class.
 219    * @param f field to add
 220    */
 221   public void addField(Field f)            { field_vec.add(f); }
 222 
 223   public boolean containsField(Field f)    { return field_vec.contains(f); }
 224 
 225   /** @return field object with given name, or null
 226    */
 227   public Field containsField(String name) {
 228     for(Iterator e=field_vec.iterator(); e.hasNext(); ) {
 229       Field f = (Field)e.next();
 230       if(f.getName().equals(name))
 231         return f;
 232     }
 233 
 234     return null;
 235   }
 236 
 237   /** @return method object with given name and signature, or null
 238    */
 239   public Method containsMethod(String name, String signature) {
 240     for(Iterator e=method_vec.iterator(); e.hasNext();) {
 241       Method m = (Method)e.next();
 242       if(m.getName().equals(name) && m.getSignature().equals(signature))
 243         return m;
 244     }
 245 
 246     return null;
 247   }
 248 
 249   /**
 250    * Remove an attribute from this class.
 251    * @param a attribute to remove
 252    */
 253   public void removeAttribute(Attribute a) { attribute_vec.remove(a); }
 254 
 255   /**
 256    * Remove a method from this class.
 257    * @param m method to remove
 258    */
 259   public void removeMethod(Method m)       { method_vec.remove(m); }
 260 
 261   /** Replace given method with new one. If the old one does not exist
 262    * add the new_ method to the class anyway.
 263    */
 264   public void replaceMethod(Method old, Method new_) {
 265     if(new_ == null)
 266       throw new ClassGenException("Replacement method must not be null");
 267 
 268     int i = method_vec.indexOf(old);
 269 
 270     if(i < 0)
 271       method_vec.add(new_);
 272     else
 273       method_vec.set(i, new_);
 274   }
 275 
 276   /** Replace given field with new one. If the old one does not exist
 277    * add the new_ field to the class anyway.
 278    */
 279   public void replaceField(Field old, Field new_) {
 280     if(new_ == null)
 281       throw new ClassGenException("Replacement method must not be null");
 282 
 283     int i = field_vec.indexOf(old);
 284 
 285     if(i < 0)
 286       field_vec.add(new_);
 287     else
 288       field_vec.set(i, new_);
 289   }
 290 
 291   /**
 292    * Remove a field to this class.
 293    * @param f field to remove
 294    */
 295   public void removeField(Field f)         { field_vec.remove(f); }
 296 
 297   public String getClassName()      { return class_name; }
 298   public String getSuperclassName() { return super_class_name; }
 299   public String getFileName()       { return file_name; }
 300 
 301   public void setClassName(String name) {
 302     class_name = name.replace('/', '.');
 303     class_name_index = cp.addClass(name);
 304   }
 305 
 306   public void setSuperclassName(String name) {
 307     super_class_name = name.replace('/', '.');
 308     superclass_name_index = cp.addClass(name);
 309   }
 310 
 311   public Method[] getMethods() {
 312     Method[] methods = new Method[method_vec.size()];
 313     method_vec.toArray(methods);
 314     return methods;
 315   }
 316 
 317   public void setMethods(Method[] methods) {
 318     method_vec.clear();
 319     for(int m=0; m<methods.length; m++)
 320       addMethod(methods[m]);
 321   }
 322 
 323   public void setMethodAt(Method method, int pos) {
 324     method_vec.set(pos, method);
 325   }
 326 
 327   public Method getMethodAt(int pos) {
 328     return (Method)method_vec.get(pos);
 329   }
 330 
 331   public String[] getInterfaceNames() {
 332     int      size = interface_vec.size();
 333     String[] interfaces = new String[size];
 334 
 335     interface_vec.toArray(interfaces);
 336     return interfaces;
 337   }
 338 
 339   public int[] getInterfaces() {
 340     int   size = interface_vec.size();
 341     int[] interfaces = new int[size];
 342 
 343     for(int i=0; i < size; i++)
 344       interfaces[i] = cp.addClass((String)interface_vec.get(i));
 345 
 346     return interfaces;
 347   }
 348 
 349   public Field[] getFields() {
 350     Field[] fields = new Field[field_vec.size()];
 351     field_vec.toArray(fields);
 352     return fields;
 353   }
 354 
 355   public Attribute[] getAttributes() {
 356     Attribute[] attributes = new Attribute[attribute_vec.size()];
 357     attribute_vec.toArray(attributes);
 358     return attributes;
 359   }
 360 
 361   public ConstantPoolGen getConstantPool() { return cp; }
 362   public void setConstantPool(ConstantPoolGen constant_pool) {
 363     cp = constant_pool;
 364   }
 365 
 366   public void setClassNameIndex(int class_name_index) {
 367     this.class_name_index = class_name_index;
 368     class_name = cp.getConstantPool().
 369       getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
 370   }
 371 
 372   public void setSuperclassNameIndex(int superclass_name_index) {
 373     this.superclass_name_index = superclass_name_index;
 374     super_class_name = cp.getConstantPool().
 375       getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
 376   }
 377 
 378   public int getSuperclassNameIndex() { return superclass_name_index; }
 379 
 380   public int getClassNameIndex()   { return class_name_index; }
 381 
 382   private ArrayList observers;
 383 
 384   /** Add observer for this object.
 385    */
 386   public void addObserver(ClassObserver o) {
 387     if(observers == null)
 388       observers = new ArrayList();
 389 
 390     observers.add(o);
 391   }
 392 
 393   /** Remove observer for this object.
 394    */
 395   public void removeObserver(ClassObserver o) {
 396     if(observers != null)
 397       observers.remove(o);
 398   }
 399 
 400   /** Call notify() method on all observers. This method is not called
 401    * automatically whenever the state has changed, but has to be
 402    * called by the user after he has finished editing the object.
 403    */
 404   public void update() {
 405     if(observers != null)
 406       for(Iterator e = observers.iterator(); e.hasNext(); )
 407         ((ClassObserver)e.next()).notify(this);
 408   }
 409 
 410   public Object clone() {
 411     try {
 412       return super.clone();
 413     } catch(CloneNotSupportedException e) {
 414       System.err.println(e);
 415       return null;
 416     }
 417   }
 418 }