/*
* Copyright (c) 2013-2015 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.model;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_DOT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SPACE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_BYTECODE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_SIG_MATCH;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_DOT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_SLASH;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import org.adoptopenjdk.jitwatch.loader.BytecodeLoader;
import org.adoptopenjdk.jitwatch.model.bytecode.ClassBC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MetaClass implements Comparable<MetaClass>
{
// private static final Logger logger =
// LoggerFactory.getLogger(MetaClass.class);
private String className;
private MetaPackage classPackage;
private boolean isInterface = false;
private boolean missingDef = false;
private List<IMetaMember> classMethods = new CopyOnWriteArrayList<IMetaMember>();
private List<IMetaMember> classConstructors = new CopyOnWriteArrayList<IMetaMember>();
private int compiledMethodCount = 0;
private ClassBC classBytecode = null;
private static final Logger logger = LoggerFactory.getLogger(MetaClass.class);
public MetaClass(MetaPackage classPackage, String className)
{
this.classPackage = classPackage;
this.className = className;
}
public IMetaMember getFirstConstructor()
{
IMetaMember result = null;
for (IMetaMember member : getMetaMembers())
{
if (member instanceof MetaConstructor)
{
result = member;
break;
}
}
return result;
}
public boolean isInterface()
{
return isInterface;
}
public void incCompiledMethodCount()
{
compiledMethodCount++;
}
public boolean hasCompiledMethods()
{
return compiledMethodCount > 0;
}
public void setInterface(boolean isInterface)
{
this.isInterface = isInterface;
}
public boolean isMissingDef()
{
return missingDef;
}
public void setMissingDef(boolean missingDef)
{
this.missingDef = missingDef;
}
public ClassBC getClassBytecode(IReadOnlyJITDataModel model, List<String> classLocations)
{
return getClassBytecode(model, classLocations, null);
}
public ClassBC getClassBytecode(IReadOnlyJITDataModel model, List<String> classLocations, Path javapPath)
{
if (DEBUG_LOGGING_BYTECODE)
{
logger.debug("getClassBytecode for {} existing? {}", getName(), classBytecode != null);
}
if (classBytecode == null)
{
classBytecode = BytecodeLoader.fetchBytecodeForClass(classLocations, getFullyQualifiedName(), javapPath, true);
if (classBytecode != null)
{
loadInnerClasses(classBytecode.getInnerClassNames(), model, classLocations);
}
}
return classBytecode;
}
public ClassBC getClassBytecode()
{
return classBytecode;
}
private void loadInnerClasses(List<String> innerClassNames, IReadOnlyJITDataModel model, List<String> classLocations)
{
if (DEBUG_LOGGING_BYTECODE)
{
logger.info("innerClasses to load {}", innerClassNames.size());
}
for (String innerClassName : innerClassNames)
{
if (DEBUG_LOGGING_BYTECODE)
{
logger.info("innerClass {}", innerClassName);
}
MetaClass metaClassForInner = model.getPackageManager().getMetaClass(innerClassName);
if (metaClassForInner != null)
{
metaClassForInner.getClassBytecode(model, classLocations);
}
else
{
logger.warn("No MetaClass found for inner Class {}", innerClassName);
}
}
}
public String toStringDetailed()
{
StringBuilder builder = new StringBuilder();
builder.append(classPackage.getName()).append(S_DOT).append(className).append(C_SPACE).append(compiledMethodCount)
.append(S_SLASH).append(classMethods.size());
return builder.toString();
}
@Override
public String toString()
{
return getName();
}
public String getName()
{
return className;
}
public String getFullyQualifiedName()
{
StringBuilder builder = new StringBuilder();
if (classPackage != null && classPackage.getName().length() > 0)
{
builder.append(classPackage.getName()).append(C_DOT);
}
builder.append(className);
return builder.toString();
}
public String getAbbreviatedFullyQualifiedName()
{
StringBuilder builder = new StringBuilder();
if (classPackage != null && classPackage.getName().length() > 0)
{
String[] parts = classPackage.getName().split("\\.");
for (String part : parts)
{
builder.append(part.charAt(0)).append(C_DOT);
}
}
builder.append(className);
return builder.toString();
}
public MetaPackage getPackage()
{
return classPackage;
}
public void addMember(IMetaMember member)
{
if (member instanceof MetaConstructor)
{
classMethods.add(member);
}
else
{
classConstructors.add(member);
}
}
public List<IMetaMember> getMetaMembers()
{
List<IMetaMember> result = new ArrayList<>();
IMetaMember[] constructorsArray = classConstructors.toArray(new IMetaMember[classConstructors.size()]);
Arrays.sort(constructorsArray);
IMetaMember[] methodsArray = classMethods.toArray(new IMetaMember[classMethods.size()]);
Arrays.sort(methodsArray);
result.addAll(Arrays.asList(constructorsArray));
result.addAll(Arrays.asList(methodsArray));
return result;
}
public IMetaMember getMemberForSignature(MemberSignatureParts msp)
{
IMetaMember result = null;
if (DEBUG_LOGGING_SIG_MATCH)
{
logger.debug("Comparing: {} members of {}", getMetaMembers().size(), this);
}
for (IMetaMember member : getMetaMembers())
{
if (member.matchesSignature(msp, true))
{
result = member;
break;
}
}
return result;
}
public List<String> getTreePath()
{
MetaPackage metaPackage = getPackage();
List<String> path = metaPackage.getPackageComponents();
path.add(getName());
return path;
}
@Override
public int compareTo(MetaClass other)
{
return this.getName().compareTo(other.getName());
}
@Override
public int hashCode()
{
return toString().hashCode();
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
else
{
return toString().equals(obj.toString());
}
}
}