001 package serp.bytecode; 002 003 import java.io.*; 004 import java.util.*; 005 006 import serp.bytecode.lowlevel.*; 007 import serp.bytecode.visitor.*; 008 009 /** 010 * Abstract superclass for all bytecode entities that hold attributes. 011 * 012 * @author Abe White 013 */ 014 public abstract class Attributes implements BCEntity { 015 /** 016 * Return all the attributes owned by this entity. 017 * 018 * @return all owned attributes, or empty array if none 019 */ 020 public Attribute[] getAttributes() { 021 Collection attrs = getAttributesHolder(); 022 return (Attribute[]) attrs.toArray(new Attribute[attrs.size()]); 023 } 024 025 /** 026 * Return the attribute with the given name. If multiple attributes 027 * share the name, which is returned is undefined. 028 */ 029 public Attribute getAttribute(String name) { 030 Collection attrs = getAttributesHolder(); 031 Attribute attr; 032 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 033 attr = (Attribute) itr.next(); 034 if (attr.getName().equals(name)) 035 return attr; 036 } 037 return null; 038 } 039 040 /** 041 * Return all attributes with the given name. 042 * 043 * @return the matching attributes, or empty array if none 044 */ 045 public Attribute[] getAttributes(String name) { 046 List matches = new LinkedList(); 047 Collection attrs = getAttributesHolder(); 048 Attribute attr; 049 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 050 attr = (Attribute) itr.next(); 051 if (attr.getName().equals(name)) 052 matches.add(attr); 053 } 054 return (Attribute[]) matches.toArray(new Attribute[matches.size()]); 055 } 056 057 /** 058 * Set the attributes for this entity; this method is useful for importing 059 * all attributes from another entity. Set to null or empty array if none. 060 */ 061 public void setAttributes(Attribute[] attrs) { 062 clearAttributes(); 063 if (attrs != null) 064 for (int i = 0; i < attrs.length; i++) 065 addAttribute(attrs[i]); 066 } 067 068 /** 069 * Import an attribute from another entity, or make a copy of one 070 * on this entity. 071 */ 072 public Attribute addAttribute(Attribute attr) { 073 Attribute newAttr = addAttribute(attr.getName()); 074 newAttr.read(attr); 075 return newAttr; 076 } 077 078 /** 079 * Add an attribute of the given type. 080 */ 081 public Attribute addAttribute(String name) { 082 Attribute attr = Attribute.create(name, this); 083 getAttributesHolder().add(attr); 084 return attr; 085 } 086 087 /** 088 * Clear all attributes from this entity. 089 */ 090 public void clearAttributes() { 091 Collection attrs = getAttributesHolder(); 092 Attribute attr; 093 for (Iterator itr = attrs.iterator(); itr.hasNext();) { 094 attr = (Attribute) itr.next(); 095 itr.remove(); 096 attr.invalidate(); 097 } 098 } 099 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 }