1 package serp.bytecode; 2 3 import java.io.*; 4 import java.util.*; 5 6 import serp.bytecode.lowlevel.*; 7 import serp.bytecode.visitor.*; 8 9 /*** 10 * Abstract superclass for all bytecode entities that hold attributes. 11 * 12 * @author Abe White 13 */ 14 public abstract class Attributes implements BCEntity { 15 /*** 16 * Return all the attributes owned by this entity. 17 * 18 * @return all owned attributes, or empty array if none 19 */ 20 public Attribute[] getAttributes() { 21 Collection attrs = getAttributesHolder(); 22 return (Attribute[]) attrs.toArray(new Attribute[attrs.size()]); 23 } 24 25 /*** 26 * Return the attribute with the given name. If multiple attributes 27 * share the name, which is returned is undefined. 28 */ 29 public Attribute getAttribute(String name) { 30 Collection attrs = getAttributesHolder(); 31 Attribute attr; 32 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 33 attr = (Attribute) itr.next(); 34 if (attr.getName().equals(name)) 35 return attr; 36 } 37 return null; 38 } 39 40 /*** 41 * Return all attributes with the given name. 42 * 43 * @return the matching attributes, or empty array if none 44 */ 45 public Attribute[] getAttributes(String name) { 46 List matches = new LinkedList(); 47 Collection attrs = getAttributesHolder(); 48 Attribute attr; 49 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 50 attr = (Attribute) itr.next(); 51 if (attr.getName().equals(name)) 52 matches.add(attr); 53 } 54 return (Attribute[]) matches.toArray(new Attribute[matches.size()]); 55 } 56 57 /*** 58 * Set the attributes for this entity; this method is useful for importing 59 * all attributes from another entity. Set to null or empty array if none. 60 */ 61 public void setAttributes(Attribute[] attrs) { 62 clearAttributes(); 63 if (attrs != null) 64 for (int i = 0; i < attrs.length; i++) 65 addAttribute(attrs[i]); 66 } 67 68 /*** 69 * Import an attribute from another entity, or make a copy of one 70 * on this entity. 71 */ 72 public Attribute addAttribute(Attribute attr) { 73 Attribute newAttr = addAttribute(attr.getName()); 74 newAttr.read(attr); 75 return newAttr; 76 } 77 78 /*** 79 * Add an attribute of the given type. 80 */ 81 public Attribute addAttribute(String name) { 82 Attribute attr = Attribute.create(name, this); 83 getAttributesHolder().add(attr); 84 return attr; 85 } 86 87 /*** 88 * Clear all attributes from this entity. 89 */ 90 public void clearAttributes() { 91 Collection attrs = getAttributesHolder(); 92 Attribute attr; 93 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 94 attr = (Attribute) itr.next(); 95 itr.remove(); 96 attr.invalidate(); 97 } 98 } 99 100 /*** 101 * Remove all attributes with the given name from this entity. 102 * 103 * @return true if an attribute was removed, false otherwise 104 */ 105 public boolean removeAttribute(String name) { 106 return removeAttribute(getAttribute(name)); 107 } 108 109 /*** 110 * Remove the given attribute. After being removed, the attribute 111 * is invalid, and the result of any operations on it are undefined. 112 * 113 * @return true if the attribute was removed, false otherwise 114 */ 115 public boolean removeAttribute(Attribute attribute) { 116 if ((attribute == null) || !getAttributesHolder().remove(attribute)) 117 return false; 118 attribute.invalidate(); 119 return true; 120 } 121 122 /*** 123 * Convenience method to be called by BCEntities when being visited 124 * by a {@link BCVisitor}; this method will allow the visitor to visit all 125 * attributes of this entity. 126 */ 127 void visitAttributes(BCVisitor visit) { 128 Attribute attr; 129 for (Iterator itr = getAttributesHolder().iterator(); itr.hasNext();) { 130 attr = (Attribute) itr.next(); 131 visit.enterAttribute(attr); 132 attr.acceptVisit(visit); 133 visit.exitAttribute(attr); 134 } 135 } 136 137 /*** 138 * Build the attribute list from the given stream. 139 * Relies on the ability of attributes to read themselves, and 140 * requires access to the constant pool, which must already by read. 141 */ 142 void readAttributes(DataInput in) throws IOException { 143 Collection attrs = getAttributesHolder(); 144 attrs.clear(); 145 146 Attribute attribute; 147 String name; 148 for (int i = in.readUnsignedShort(); i > 0; i--) { 149 name = ((UTF8Entry) getPool().getEntry(in.readUnsignedShort())). 150 getValue(); 151 attribute = addAttribute(name); 152 attribute.read(in, in.readInt()); 153 } 154 } 155 156 /*** 157 * Writes all the owned attributes to the given stream. 158 * Relies on the ability of attributes to write themselves. 159 */ 160 void writeAttributes(DataOutput out) throws IOException { 161 Collection attrs = getAttributesHolder(); 162 out.writeShort(attrs.size()); 163 164 Attribute attribute; 165 int length; 166 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 167 attribute = (Attribute) itr.next(); 168 out.writeShort(attribute.getNameIndex()); 169 length = attribute.getLength(); 170 out.writeInt(length); 171 attribute.write(out, length); 172 } 173 } 174 175 /*** 176 * Return the collection used to hold the attributes of this entity. 177 */ 178 abstract Collection getAttributesHolder(); 179 }