001: /*
002: Copyright (c) 2003-2005, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.binding.classes;
030:
031: import org.apache.bcel.Constants;
032: import org.apache.bcel.classfile.ExceptionTable;
033: import org.apache.bcel.classfile.Method;
034:
035: /**
036: * Binding method information. Tracks a method used by the binding code,
037: * supplying hash code and equality checking based on the method signature and
038: * actual byte code of the method, ignoring the method name. This allows
039: * comparisons between methods generated by different bindings, and between
040: * generated and existing methods.
041: *
042: * @author Dennis M. Sosnoski
043: * @version 1.0
044: */
045:
046: public abstract class BindingMethod {
047: /** Owning class file information. */
048: private ClassFile m_classFile;
049:
050: /**
051: * Constructor.
052: *
053: * @param cf owning class file information
054: */
055:
056: protected BindingMethod(ClassFile cf) {
057: m_classFile = cf;
058: }
059:
060: /**
061: * Get class file containing method.
062: *
063: * @return class file owning this method
064: */
065:
066: public ClassFile getClassFile() {
067: return m_classFile;
068: }
069:
070: /**
071: * Get name of method. This abstract method must be implemented by every
072: * subclass.
073: *
074: * @return method name
075: */
076:
077: public abstract String getName();
078:
079: /**
080: * Get signature. This abstract method must be implemented by every
081: * subclass.
082: *
083: * @return signature for method
084: */
085:
086: public abstract String getSignature();
087:
088: /**
089: * Get access flags. This abstract method must be implemented by every
090: * subclass.
091: *
092: * @return flags for access type of method
093: */
094:
095: public abstract int getAccessFlags();
096:
097: /**
098: * Set access flags. This abstract method must be implemented by every
099: * subclass.
100: *
101: * @param flags access type to be set
102: */
103:
104: public abstract void setAccessFlags(int flags);
105:
106: /**
107: * Get the actual method.
108: *
109: * @return method information
110: */
111:
112: public abstract Method getMethod();
113:
114: /**
115: * Get the method item.
116: *
117: * @return method item information
118: */
119:
120: public abstract ClassItem getItem();
121:
122: /**
123: * Make accessible method. Check if this method is accessible from another
124: * class, and if not decreases the access restrictions to make it
125: * accessible.
126: *
127: * @param src class file for required access
128: */
129:
130: public void makeAccessible(ClassFile src) {
131:
132: // no need to change if already public access
133: int access = getAccessFlags();
134: if ((access & Constants.ACC_PUBLIC) == 0) {
135:
136: // check for same package as most restrictive case
137: ClassFile dest = getClassFile();
138: if (dest.getPackage().equals(src.getPackage())) {
139: if ((access & Constants.ACC_PRIVATE) != 0) {
140: access = access - Constants.ACC_PRIVATE;
141: }
142: } else {
143:
144: // check if access is from a subclass of this method class
145: ClassFile ancestor = src;
146: while ((ancestor = ancestor.getSuperFile()) != null) {
147: if (ancestor == dest) {
148: break;
149: }
150: }
151:
152: // handle access adjustments based on subclass status
153: if (ancestor == null) {
154: int clear = Constants.ACC_PRIVATE
155: | Constants.ACC_PROTECTED;
156: access = (access & ~clear) | Constants.ACC_PUBLIC;
157: } else if ((access & Constants.ACC_PROTECTED) == 0) {
158: access = (access & ~Constants.ACC_PRIVATE)
159: | Constants.ACC_PROTECTED;
160: }
161: }
162:
163: // set new access flags
164: if (access != getAccessFlags()) {
165: setAccessFlags(access);
166: }
167: }
168: }
169:
170: /**
171: * Computes the hash code for a method. The hash code is based on the
172: * method signature, the exceptions thrown, and the actual byte code
173: * (including the exception handlers).
174: *
175: * @return computed hash code for method
176: */
177:
178: public static int computeMethodHash(Method method) {
179: int hash = method.getSignature().hashCode();
180: ExceptionTable etab = method.getExceptionTable();
181: if (etab != null) {
182: String[] excepts = etab.getExceptionNames();
183: for (int i = 0; i < excepts.length; i++) {
184: hash += excepts[i].hashCode();
185: }
186: }
187: byte[] code = method.getCode().getCode();
188: for (int i = 0; i < code.length; i++) {
189: hash = hash * 49 + code[i];
190: }
191: return hash;
192: }
193:
194: /**
195: * Get hash code. This abstract method must be implemented by every
196: * subclass, using the same algorithm in each case. See one of the existing
197: * subclasses for details.
198: *
199: * @return hash code for this method
200: */
201:
202: public abstract int hashCode();
203:
204: /**
205: * Check if objects are equal. Compares first based on hash code, then on
206: * the actual byte code sequence.
207: *
208: * @return <code>true</code> if equal objects, <code>false</code> if not
209: */
210:
211: public boolean equals(Object obj) {
212: if (obj instanceof BindingMethod) {
213: BindingMethod comp = (BindingMethod) obj;
214: if (hashCode() == comp.hashCode()
215: && getSignature().equals(comp.getSignature())) {
216: return ClassFile.equalMethods(this .getMethod(), comp
217: .getMethod());
218: }
219: }
220: return false;
221: }
222: }
|