package jdepend.model.result;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import jdepend.framework.exception.JDependException;
import jdepend.framework.util.MathUtil;
import jdepend.framework.util.MetricsFormat;
import jdepend.metadata.JavaClassRelationItem;
import jdepend.metadata.JavaPackage;
import jdepend.metadata.Method;
import jdepend.metadata.tree.JavaPackageNode;
import jdepend.metadata.tree.JavaPackageTreeCreator;
import jdepend.metadata.util.JavaClassCollection;
import jdepend.metadata.util.JavaClassUtil;
import jdepend.model.AreaComponent;
import jdepend.model.Component;
import jdepend.model.JDependUnit;
import jdepend.model.JavaClassUnit;
import jdepend.model.Relation;
import jdepend.model.area.AreaCreatorChain;
import jdepend.model.component.MemoryComponent;
import jdepend.model.util.CopyUtil;
import jdepend.model.util.JavaClassUnitUtil;
import jdepend.model.util.RelationCreator;
public class AnalysisResult extends AnalysisResultScored implements Serializable {
private static final long serialVersionUID = -8130705071313304937L;
private List<Component> components;
private AnalysisRunningContext runningContext;
private transient AnalysisResultSummary summary;
private transient Collection<Relation> relations;
private transient Collection<JavaClassUnit> javaClasses;
private transient Collection<JavaPackage> javaPackages;// 包含在Component中的包集合
private transient Float normalRelation = null;// 没有问题的关系比重(考虑了问题权重)
private transient Float tableRelationScale = null;// tableRelation比例
private transient byte[] data = null;// result字节数据
private transient Map<String, Component> componentForNames;
private transient Map<String, JavaClassUnit> javaClassForIds;
private transient List<AreaComponent> areaComponents;
private transient boolean isExecuteResult = false;
private transient JavaPackageNode javaPackageTree;
private transient Collection<Method> methods;
private transient Map<String, JavaClassRelationItem> javaClassRelationItems;
public static final String Metrics_D = "Result_Metrics_D";
public static final String Metrics_Balance = "Result_Metrics_Balance";
public static final String Metrics_RelationRationality = "Result_Metrics_RelationRationality";
public static final String Metrics_Encapsulation = "Result_Metrics_Encapsulation";
public static final String Metrics_TotalScore = "Result_Metrics_TotalScore";
public static final String Metrics_LC = "Result_Metrics_LC";
public static final String Metrics_CN = "Result_Metrics_CN";
public static final String Metrics_ComponentCount = "Result_Metrics_ComponentCount";
public static final String Metrics_RelationCount = "Result_Metrics_RelationCount";
public static final String Metrics_RelationComponentScale = "Result_Metrics_RelationComponentScale";
public static final String Metrics_Coupling = "Result_Metrics_Coupling";
public static final String Metrics_Cohesion = "Result_Metrics_Cohesion";
public AnalysisResult(List<Component> components, AnalysisRunningContext runningContext) {
super();
this.runningContext = runningContext;
this.components = components;
this.init();
}
public AnalysisResult(AnalysisResult result) {
this.runningContext = result.runningContext;
this.components = result.components;
for (Component component : this.components) {
component.setResult(this);
}
this.areaComponents = result.areaComponents;
this.isExecuteResult = result.isExecuteResult;
this.relations = result.relations;
this.summary = result.summary;
this.data = result.data;
this.tableRelationScale = result.tableRelationScale;
this.componentForNames = result.componentForNames;
this.javaClassForIds = result.javaClassForIds;
this.methods = result.methods;
this.javaClasses = result.javaClasses;
this.javaPackages = result.javaPackages;
this.javaPackageTree = result.javaPackageTree;
}
private void init() {
// 填充Result
for (Component component : this.components) {
component.setResult(this);
}
// 计算关系
this.calRelations();
// 重新计算组件区域
this.calAreaComponents();
// 初始化Relations
this.initRelations();
}
public List<Component> getComponents() {
return components;
}
public void setComponents(List<Component> components) {
this.components = components;
for (Component component : this.components) {
component.setResult(this);
}
this.componentForNames = null;
this.javaClasses = null;
this.javaPackages = null;
this.javaClassForIds = null;
}
public AnalysisRunningContext getRunningContext() {
return runningContext;
}
public void setRunningContext(AnalysisRunningContext runningContext) {
this.runningContext = runningContext;
}
public synchronized Collection<JavaClassUnit> getClasses() {
if (javaClasses == null) {
javaClasses = JavaClassUnitUtil.getClasses(components);
}
return javaClasses;
}
public synchronized Collection<JavaPackage> getJavaPackages() {
if (javaPackages == null) {
javaPackages = JavaClassUnitUtil.getJavaPackages(components);
}
return javaPackages;
}
public synchronized JavaPackageNode getJavaPackageTree() {
if (this.javaPackageTree == null) {
this.javaPackageTree = (new JavaPackageTreeCreator()).createTree(getJavaPackages());
}
return javaPackageTree;
}
public synchronized JavaClassUnit getTheClass(String id) {
if (javaClassForIds == null) {
javaClassForIds = new HashMap<String, JavaClassUnit>();
for (JavaClassUnit javaClass : getClasses()) {
javaClassForIds.put(javaClass.getId(), javaClass);
for (JavaClassUnit innerClassUnit : javaClass.getInnerClassUnits()) {
javaClassForIds.put(innerClassUnit.getId(), innerClassUnit);
}
}
}
return javaClassForIds.get(id);
}
public synchronized Collection<Method> getMethods() {
if (this.methods == null) {
this.methods = new HashSet<Method>();
for (JavaClassUnit javaClass : this.getClasses()) {
for (Method method : javaClass.getJavaClass().getSelfMethods()) {
this.methods.add(method);
}
}
}
return this.methods;
}
public synchronized JavaClassRelationItem getTheJavaClassRelationItem(String id) {
if (this.javaClassRelationItems == null) {
this.javaClassRelationItems = new HashMap<String, JavaClassRelationItem>();
for (JavaClassUnit javaClass : this.getClasses()) {
for (JavaClassRelationItem item : javaClass.getJavaClass().getRelationItems()) {
this.javaClassRelationItems.put(item.getId(), item);
}
}
}
return this.javaClassRelationItems.get(id);
}
public boolean isEmpty() {
return this.components == null || this.components.size() == 0;
}
protected boolean hasRelation() {
return this.getRelations() != null && this.getRelations().size() > 0;
}
public Component getTheComponent(String componentName) {
return this.getComponentForNames().get(componentName);
}
public synchronized Component deleteTheComponent(String name) {
Component deleteComponent = null;
for (Component component : this.components) {
if (component.getName().equals(name)) {
deleteComponent = component;
this.components.remove(component);
break;
}
}
// 删除JavaClass间的关系
if (deleteComponent != null) {
if (this.componentForNames != null) {
this.componentForNames.remove(deleteComponent.getName());
}
Iterator<JavaClassRelationItem> it;
for (JavaClassUnit javaClass : deleteComponent.getClasses()) {
for (JavaClassUnit dependClass : javaClass.getCaList()) {
it = dependClass.getJavaClass().getCeItems().iterator();
while (it.hasNext()) {
if (it.next().getTarget().equals(javaClass)) {
it.remove();
}
}
}
for (JavaClassUnit dependClass : javaClass.getCeList()) {
it = dependClass.getJavaClass().getCaItems().iterator();
while (it.hasNext()) {
if (it.next().getSource().equals(javaClass)) {
it.remove();
}
}
}
}
}
return deleteComponent;
}
public synchronized boolean addComponent(String componentName, int componentLayer) {
MemoryComponent newComponent = new MemoryComponent(componentName);
newComponent.setLayer(componentLayer);
return addComponent(newComponent);
}
public synchronized boolean addComponent(Component component) {
if (!this.components.contains(component)) {
this.components.add(component);
component.setResult(this);
if (this.componentForNames != null) {
this.componentForNames.put(component.getName(), component);
}
return true;
} else {
return false;
}
}
public synchronized AnalysisResultSummary getSummary() {
if (this.summary == null) {
this.summary = new AnalysisResultSummary(this);
}
return this.summary;
}
@Override
public float getNormalRelation() {
if (this.normalRelation == null) {
this.normalRelation = 1 - new AnalysisResultUtil(this).calAttentionRelation();
}
return normalRelation;
}
/**
* 计算存在问题的关系的比例
*
* @return
*/
public float getAttentionRelationScale() {
return new AnalysisResultUtil(this).getAttentionRelationScale();
}
/**
* 基于数据库表实现组件间通讯的比例
*
* @return
*/
public synchronized float calTableRelationScale() {
if (this.tableRelationScale == null) {
this.tableRelationScale = new AnalysisResultUtil(this).tableRelationScale();
}
return this.tableRelationScale;
}
/**
* 返回关系个数和组件个数的比值
*
* @return
*/
public float calRelationComponentScale() {
if (this.getComponents().size() > 0) {
return MetricsFormat.toFormattedMetrics(this.getRelations().size() * 1F / this.getComponents().size());
} else {
return 0F;
}
}
/**
* 计算平均类大小
*
* @return
*/
public int calClassSize() {
return new AnalysisResultUtil(this).calClassSize();
}
public synchronized Collection<Relation> getRelations() {
if (this.relations == null) {
this.calRelations();
}
return this.relations;
}
public synchronized List<AreaComponent> getAreaComponents() {
if (this.areaComponents == null) {
this.calAreaComponents();
}
return this.areaComponents;
}
private void calRelations() {
this.relations = new RelationCreator().create(components);
}
private void calAreaComponents() {
if (this.runningContext.getProfileFacade().getAreaComponentProfile().isCreate()) {
this.areaComponents = new AreaCreatorChain(this).create();
} else {
this.areaComponents = new ArrayList<AreaComponent>();
}
}
private void initRelations() {
for (final Relation relation : this.getRelations()) {
relation.init();
}
}
public Relation getTheRelation(String current, String depend) {
for (Relation r : this.getRelations()) {
if (r.equals(current, depend)) {
return r;
}
}
return null;
}
private synchronized Map<String, Component> getComponentForNames() {
if (this.componentForNames == null) {
this.componentForNames = new HashMap<String, Component>();
for (Component unit : this.components) {
this.componentForNames.put(unit.getName(), unit);
}
}
return this.componentForNames;
}
/**
* 得到与配置信息存在差异的elements
*
* @return
*/
public Map<String, String> getDiffElements() {
if (this.isExecuteResult) {
return this.runningContext.getDiffElements();
} else {
return null;
}
}
public void clearCache() {
// 清空自身内容
this.relations = null;
this.summary = null;
this.data = null;
this.normalRelation = null;
this.tableRelationScale = null;
this.componentForNames = null;
this.javaClassForIds = null;
this.methods = null;
this.javaClassRelationItems = null;
this.clearScore();
// 清空Component的缓存信息
for (JDependUnit unit : this.getComponents()) {
unit.clear();
}
// 清空JavaClass的缓存信息
for (JavaClassUnit javaClass : getClasses()) {
javaClass.clear();
}
this.javaClasses = null;
this.javaPackages = null;
this.javaPackageTree = null;
// 重新计算relations
this.calRelations();
// 重新计算组件区域
this.calAreaComponents();
}
public void clearRelationCache() {
for (Relation relation : this.relations) {
relation.clear();
}
}
public boolean isExecuteResult() {
return isExecuteResult;
}
public void setExecuteResult(boolean isExecuteResult) {
this.isExecuteResult = isExecuteResult;
}
public AnalysisResult clone() {
List<Component> newComponents = (new CopyUtil()).copy(runningContext, this.components);
return new AnalysisResult(newComponents, this.runningContext);
}
public byte[] sequence() throws IOException {
return getBytes();
}
private byte[] getBytes() throws IOException {
if (this.data == null) {
ByteArrayOutputStream outstream = null;
GZIPOutputStream gzip = null;
ObjectOutputStream out = null;
try {
outstream = new ByteArrayOutputStream();
gzip = new GZIPOutputStream(outstream);
out = new ObjectOutputStream(gzip);
out.writeObject(this);
out.flush();
gzip.flush();
gzip.finish();
outstream.flush();
this.data = outstream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outstream != null) {
try {
outstream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (gzip != null) {
try {
gzip.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return this.data;
}
public static AnalysisResult create(byte[] data) throws IOException, ClassNotFoundException {
return create(data, null);
}
public static AnalysisResult create(byte[] data, AnalysisResultUnSequenceListener listener) throws IOException,
ClassNotFoundException {
InputStream inputstream = null;
GZIPInputStream gzip = null;
ObjectInputStream in = null;
try {
inputstream = new ByteArrayInputStream(data);
gzip = new GZIPInputStream(inputstream);
in = new ObjectInputStream(gzip);
AnalysisResult result = (AnalysisResult) in.readObject();
result.unSequence(listener);
return result;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (gzip != null) {
try {
gzip.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputstream != null) {
try {
inputstream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void unSequence() {
this.unSequence(null);
}
public void unSequence(AnalysisResultUnSequenceListener listener) {
if (listener != null) {
listener.onUnSequence("正在创建类集合");
}
JavaClassCollection javaClasses = new JavaClassCollection(this.getRunningContext().getProfileFacade()
.getJavaClassRelationItemProfile().getJavaClassRelationTypes(),
JavaClassUnitUtil.getAllClasses(components));
// 填充JavaClassRelationItem
if (listener != null) {
listener.onUnSequence("正在填充类关系");
}
JavaClassUtil.supplyJavaClassRelationItem(javaClasses);
// 填充Method中的InvokeItem中的Method
if (listener != null) {
listener.onUnSequence("正在填充类细节");
}
JavaClassUtil.supplyJavaClassDetail(javaClasses);
// 初始化
this.init();
}
@Override
public String toString() {
StringBuilder info = new StringBuilder();
info.append(this.getRunningContext());
info.append("\n");
info.append(this.getSummary());
info.append("\n");
info.append(this.getScoreInfo());
info.append("\n");
info.append("基于数据库表实现组件间通讯的比例:");
info.append(MetricsFormat.toFormattedPercent(this.calTableRelationScale()));
info.append("关系个数与组件个数的比值:");
info.append(this.calRelationComponentScale());
info.append("\n");
return info.toString();
}
private StringBuilder getScoreInfo() {
StringBuilder scoreInfo = new StringBuilder();
scoreInfo.append("最终得分:");
scoreInfo.append(this.getScore());
scoreInfo.append("(抽象程度合理性得分:");
scoreInfo.append(this.getDistance());
scoreInfo.append("【满分:" + this.getDistanceScale() + "】 内聚性得分:");
scoreInfo.append(this.getBalance());
scoreInfo.append("【满分:" + this.getBalanceScale() + "】 内聚性得分:】封装性得分:");
scoreInfo.append(this.getEncapsulation());
scoreInfo.append("【满分:" + this.getEncapsulationScale() + "】 关系合理性得分:");
scoreInfo.append(this.getRelationRationality());
scoreInfo.append("【满分:" + this.getRelationRationalityScale() + "】)\n");
return scoreInfo;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((this.getRunningContext().getCommand() == null) ? 0 : this.getRunningContext().getCommand()
.hashCode());
result = prime * result
+ ((this.getRunningContext().getGroup() == null) ? 0 : this.getRunningContext().getGroup().hashCode());
result = prime * result + new Integer(this.getSummary().getLineCount()).hashCode();
result = prime * result + new Float(this.getScore()).hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AnalysisResult other = (AnalysisResult) obj;
if (!runningContext.equals(other.runningContext))
return false;
if (!this.getSummary().equals(other.getSummary()))
return false;
return true;
}
public StringBuilder compare(AnalysisResult result) throws JDependException {
if (result == null) {
throw new JDependException("参数不能为空");
}
if (!this.getRunningContext().getGroup().equals(result.getRunningContext().getGroup())
|| !this.getRunningContext().getCommand().equals(result.getRunningContext().getCommand())) {
throw new JDependException("不同命令的分析结果不能比较");
}
StringBuilder diff = new StringBuilder();
List<ItemDiff> itemDiffs = new ArrayList<ItemDiff>();
itemDiffs.add(new ItemDiff("组件个数", this.getComponents().size(), result.getComponents().size()));
itemDiffs.add(new ItemDiff("关系个数", this.getRelations().size(), result.getRelations().size()));
itemDiffs
.add(new ItemDiff("关系个数与组件个数的比值", this.calRelationComponentScale(), result.calRelationComponentScale()));
itemDiffs.add(new ItemDiff("总分", this.getScore(), result.getScore()));
itemDiffs.add(new ItemDiff("抽象程度合理性得分", this.getDistance(), result.getDistance()));
itemDiffs.add(new ItemDiff("内聚性得分", this.getBalance(), result.getBalance()));
itemDiffs.add(new ItemDiff("封装性得分", this.getEncapsulation(), result.getEncapsulation()));
itemDiffs.add(new ItemDiff("关系合理性得分", this.getRelationRationality(), result.getRelationRationality()));
itemDiffs.add(new ItemDiff("耦合值", this.getSummary().getCoupling(), result.getSummary().getCoupling()));
itemDiffs.add(new ItemDiff("内聚值", this.getSummary().getCohesion(), result.getSummary().getCohesion()));
String itemDiffDesc;
for (ItemDiff itemDiff : itemDiffs) {
itemDiffDesc = itemDiff.toString();
if (itemDiffDesc != null) {
diff.append(itemDiffDesc);
}
}
if (diff.length() == 0) {
return null;
} else {
return diff;
}
}
class ItemDiff {
private String item;
private Comparable o1;
private Comparable o2;
public ItemDiff(String item, Comparable o1, Comparable o2) {
super();
this.item = item;
this.o1 = o1;
this.o2 = o2;
}
@Override
public String toString() {
if (!MathUtil.isEquals(o1, o2)) {
StringBuilder diff = new StringBuilder();
diff.append(item);
if (o1.compareTo(o2) == -1) {
diff.append("下降");
} else {
diff.append("升高");
}
diff.append(",当前为[");
diff.append(o1);
diff.append("],之前为[");
diff.append(o2);
diff.append("]。\n");
return diff.toString();
} else {
return null;
}
}
}
@Override
public float getDistanceScale() {
return this.runningContext.getProfileFacade().getAnalysisResultProfile().getDistance();
}
@Override
public float getBalanceScale() {
return this.runningContext.getProfileFacade().getAnalysisResultProfile().getBalance();
}
@Override
public float getEncapsulationScale() {
return this.runningContext.getProfileFacade().getAnalysisResultProfile().getEncapsulation();
}
@Override
public float getRelationRationalityScale() {
return this.runningContext.getProfileFacade().getAnalysisResultProfile().getRelationRationality();
}
}