| /********************************************************************** |
| * Copyright (c) 2002, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| �* |
| * Contributors: |
| * IBM - Initial API and implementation |
| **********************************************************************/ |
| |
| package org.eclipse.wtp.releng.tools.component.internal; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.Vector; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.core.util.ClassFormatException; |
| import org.eclipse.jdt.core.util.IClassFileReader; |
| import org.eclipse.jdt.core.util.ICodeAttribute; |
| import org.eclipse.jdt.core.util.IConstantPool; |
| import org.eclipse.jdt.core.util.IConstantPoolConstant; |
| import org.eclipse.jdt.core.util.IConstantPoolEntry; |
| import org.eclipse.jdt.core.util.IFieldInfo; |
| import org.eclipse.jdt.core.util.ILineNumberAttribute; |
| import org.eclipse.jdt.core.util.IMethodInfo; |
| import org.eclipse.jdt.core.util.IModifierConstants; |
| import org.eclipse.jdt.internal.core.util.ClassFileReader; |
| import org.eclipse.wtp.releng.tools.component.IClazz; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| |
| /** |
| * A <code>Clazz</code> is a model object. Clazz contain references to other |
| * Clazz. |
| */ |
| public class Clazz implements IClazz |
| { |
| private ILocation location; |
| private String name; |
| private IClassFileReader reader; |
| private List methodRefs; |
| private List fieldRefs; |
| |
| /** |
| * Creates a new type on the given location. |
| * |
| * @param location |
| */ |
| public Clazz(ILocation location) |
| { |
| this.location = location; |
| reader = null; |
| } |
| |
| private void init() |
| { |
| if (reader == null) |
| { |
| try |
| { |
| reader = new ClassFileReader(getInputBytes(), IClassFileReader.CONSTANT_POOL | IClassFileReader.METHOD_INFOS | IClassFileReader.FIELD_INFOS | IClassFileReader.METHOD_BODIES); |
| } |
| catch (ClassFormatException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| protected byte[] getInputBytes() throws IOException |
| { |
| InputStream in = null; |
| byte[] fBuffer = new byte[8192]; |
| ByteArrayOutputStream fBytesOut = new ByteArrayOutputStream(8192); |
| try |
| { |
| fBytesOut.reset(); |
| in = location.getInputStream(); |
| for (int read = in.read(fBuffer); read != -1; read = in.read(fBuffer)) |
| { |
| fBytesOut.write(fBuffer, 0, read); |
| } |
| } |
| catch (FileNotFoundException e) |
| { |
| e.printStackTrace(); |
| } |
| finally |
| { |
| in.close(); |
| } |
| return fBytesOut.toByteArray(); |
| } |
| |
| /** |
| * @return Set a set of <code>InternalTypeReference</code> objects |
| */ |
| public Set getReferencedTypes() |
| { |
| init(); |
| Set types = new HashSet(); |
| IConstantPool constantPool = reader.getConstantPool(); |
| int poolSize = constantPool.getConstantPoolCount(); |
| for (int i = 0; i < poolSize; i++) |
| { |
| // Extract the constant's referenced class (if that is even relevant) |
| if (constantPool.getEntryKind(i) == IConstantPoolConstant.CONSTANT_Class) |
| { |
| IConstantPoolEntry classEntry = constantPool.decodeEntry(i); |
| String signature = new String(classEntry.getClassInfoName()); |
| int index = signature.lastIndexOf('['); |
| if (index > -1) |
| { |
| // could be an array of a primitive type |
| if (signature.length() - (index + 1) == 1) |
| continue; |
| signature = Signature.toString(signature); |
| signature = signature.substring(0, signature.length() - 2 * (index + 1)); |
| signature = signature.replace('.', '$'); |
| } |
| String typeName = signature.replace('/', '.'); |
| types.add(typeName); |
| } |
| } |
| return types; |
| } |
| |
| public List getMethodRefs(List includes, List excludes, boolean genLineInfo) |
| { |
| if (methodRefs == null) |
| getRefs(includes, excludes, genLineInfo); |
| return methodRefs; |
| } |
| |
| public void resetMethodRefs() |
| { |
| methodRefs = null; |
| } |
| |
| public List getFieldRefs(List includes, List excludes, boolean genLineInfo) |
| { |
| if (fieldRefs == null) |
| getRefs(includes, excludes, genLineInfo); |
| return fieldRefs; |
| } |
| |
| public void resetFieldRefs() |
| { |
| fieldRefs = null; |
| } |
| |
| private void getRefs(List includes, List excludes, boolean debug) |
| { |
| methodRefs = new ArrayList(1); |
| fieldRefs = new ArrayList(1); |
| IConstantPoolEntry[] refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Methodref); |
| for (int i = 0; i < refs.length; i++) |
| { |
| if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName()))) |
| { |
| MethodRef methodRef = new MethodRef(); |
| methodRef.setPoolEntry(refs[i]); |
| methodRefs.add(methodRef); |
| } |
| } |
| refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_InterfaceMethodref); |
| for (int i = 0; i < refs.length; i++) |
| { |
| if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName()))) |
| { |
| MethodRef methodRef = new MethodRef(); |
| methodRef.setPoolEntry(refs[i]); |
| methodRefs.add(methodRef); |
| } |
| } |
| refs = getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Fieldref); |
| for (int i = 0; i < refs.length; i++) |
| { |
| if (isIncludeClass(includes, excludes, decodeClassName(refs[i].getClassName()))) |
| { |
| FieldRef fieldRef = new FieldRef(); |
| fieldRef.setPoolEntry(refs[i]); |
| fieldRefs.add(fieldRef); |
| } |
| } |
| if (debug) |
| { |
| IMethodInfo[] methodInfos = getMethodInfo(); |
| for (int i = 0; i < methodInfos.length; i++) |
| { |
| ICodeAttribute codeAttr = methodInfos[i].getCodeAttribute(); |
| if (codeAttr != null) |
| { |
| ILineNumberAttribute lineNumAttr = codeAttr.getLineNumberAttribute(); |
| if (lineNumAttr != null) |
| { |
| InternalByteCodeVisitor byteCodeVisitor = new InternalByteCodeVisitor(methodRefs, fieldRefs, lineNumAttr); |
| try |
| { |
| codeAttr.traverse(byteCodeVisitor); |
| } |
| catch (ClassFormatException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * @return String the fully qualified name of the type |
| */ |
| public String getName() |
| { |
| if (name == null) |
| { |
| init(); |
| name = decodeClassName(reader.getClassName()); |
| } |
| return name; |
| } |
| |
| public String getSuperClass() |
| { |
| init(); |
| char[] superClass = reader.getSuperclassName(); |
| if (superClass != null) |
| return decodeClassName(superClass); |
| else |
| return null; |
| } |
| |
| public String[] getInterfaces() |
| { |
| init(); |
| char[][] interfaceNames = reader.getInterfaceNames(); |
| String[] interfaces = new String[interfaceNames.length]; |
| for (int i = 0; i < interfaces.length; i++) |
| interfaces[i] = decodeClassName(interfaceNames[i]); |
| return interfaces; |
| } |
| |
| public IFieldInfo[] getFieldInfo() |
| { |
| init(); |
| return reader.getFieldInfos(); |
| } |
| |
| public IMethodInfo[] getMethodInfo() |
| { |
| init(); |
| return reader.getMethodInfos(); |
| } |
| |
| public IConstantPoolEntry[] getConstantPoolEntries(int kind) |
| { |
| init(); |
| List entries = new Vector(); |
| IConstantPool pool = reader.getConstantPool(); |
| int poolSize = pool.getConstantPoolCount(); |
| for (int i = 0; i < poolSize; i++) |
| if (pool.getEntryKind(i) == kind) |
| entries.add(pool.decodeEntry(i)); |
| return (IConstantPoolEntry[])entries.toArray(new IConstantPoolEntry[0]); |
| } |
| |
| public boolean isInterface() |
| { |
| init(); |
| return ((reader.getAccessFlags() & IModifierConstants.ACC_INTERFACE) == IModifierConstants.ACC_INTERFACE); |
| } |
| |
| public int getAccessFlags() |
| { |
| init(); |
| return reader.getAccessFlags(); |
| } |
| |
| private String decodeClassName(char[] name) |
| { |
| return new String(name).replace('/', '.'); |
| } |
| |
| private boolean isIncludeClass(List classIncludes, List classExcludes, String className) |
| { |
| if (classExcludes != null) |
| for (Iterator it = classExcludes.iterator(); it.hasNext();) |
| if (className.startsWith((String)it.next())) |
| return false; |
| if (classIncludes != null && classIncludes.size() > 0) |
| { |
| for (Iterator it = classIncludes.iterator(); it.hasNext();) |
| if (className.startsWith((String)it.next())) |
| return true; |
| return false; |
| } |
| return true; |
| } |
| |
| public void resetClazz() |
| { |
| reader = null; |
| methodRefs = null; |
| fieldRefs = null; |
| } |
| } |