Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
starkda committed Apr 17, 2024
1 parent 202e99e commit bb8e09f
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 171 deletions.
211 changes: 62 additions & 149 deletions src/main/java/org/jpeek/calculus/java/Ccm.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,18 @@

import com.jcabi.xml.XML;
import com.jcabi.xml.XSL;
import com.jcabi.xml.XSLChain;
import com.jcabi.xml.XSLDocument;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.cactoos.io.ResourceOf;
import org.cactoos.io.UncheckedInput;
import org.cactoos.text.FormattedText;
import org.jpeek.XslReport;
import org.jpeek.calculus.Calculus;
import org.jpeek.calculus.java.implementations.UnionFind;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.jpeek.graph.Disjoint;
import org.jpeek.graph.XmlGraph;

/**
* CCM metric Java calculus.
Expand All @@ -63,159 +58,77 @@ public XML node(
).toString()
);
}
final XSLDocument doc = new XSLDocument(
List<XSL> layers = new ArrayList<>(0);
if (!params.containsKey("include-static-methods")) {
layers = addXslFilter(layers, "no-static-methods.xsl");
}
if (!params.containsKey("include-ctors")) {
layers = addXslFilter(layers, "no-ctors.xsl");
}
if (!params.containsKey("include-private-methods")) {
layers = addXslFilter(layers, "no-private-methods.xsl");
}
final XSLChain chain = new XSLChain(layers);
final XML meta = new XSLDocument(
XslReport.class.getResourceAsStream(
"xsl/meta/meta-creater.xsl"
)
).transform(chain.transform(skeleton));
final XML modified = findNcc(skeleton, meta);
return new XSLDocument(
new UncheckedInput(
new ResourceOf("org/jpeek/metrics/CCM.xsl")
).stream()
);
final XML meta = addMetaInformation(skeleton, params);
return doc.transform(meta);
}

/**
* Adds meta information to the skeleton XML document.
* This method modifies the skeleton XML document by adding meta information
* about the computed CCM metric.
* @param skeleton The skeleton XML document representing the code structure.
* @param params Parameters for the computation.
* @return The modified XML document containing meta information.
*/
private static XML addMetaInformation(final XML skeleton, final Map<String, Object> params) {
try {
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.newDocument();
final Element meta = doc.createElement("meta");
final List<XML> packages = skeleton.nodes("//package");
for (final XML pack : packages) {
final Element tag = doc.createElement("package");
tag.setAttribute(
"id", pack.node().getAttributes().getNamedItem("id").getNodeValue()
);
final List<XML> classes = pack.nodes("class");
for (final XML clazz: classes) {
final Element sub = doc.createElement("class");
sub.appendChild(addNccTag(doc, clazz, params));
sub.setAttribute(
"id",
clazz.node().getAttributes().getNamedItem("id").getNodeValue()
);
tag.appendChild(sub);
}
meta.appendChild(tag);
}
final XSL modifier = new XSLDocument(
XslReport.class.getResourceAsStream(
"xsl/meta-info.xsl"
)
).with("meta", meta);
return modifier.transform(skeleton);
} catch (final ParserConfigurationException ex) {
throw new IllegalStateException(ex);
}
}

/**
* Adds NCC (Number of Component Connections) tag to the XML document.
* This method calculates the NCC for a given class and adds it as a tag to the XML document.
* @param doc The XML document to which the NCC tag will be added.
* @param clazz The XML representation of the class.
* @param params Parameters for the computation (unused).
* @return The NCC node.
*/
private static Node addNccTag(final Document doc, final XML clazz,
final Map<String, Object> params
) {
final Element ncc = doc.createElement("ncc");
ncc.appendChild(doc.createTextNode(calculateComponents(clazz, params).toString()));
return ncc;
).transform(modified);
}

/**
* Calculates the number of components for a given class.
* This method calculates the number of components for a class using the Union-Find algorithm.
* @param clazz The XML representation of the class.
* @param params Parameters for the computation.
* @return The number of components.
* Find NCC.
*
* @param skeleton The XML skeleton to operate on
* @param meta The XML containing metadata
* @return The modified XML
*/
private static Integer calculateComponents(final XML clazz, final Map<String, Object> params) {
final Map<String, List<String>> connections = new HashMap<>();
final Map<String, String> parents = new HashMap<>();
final List<XML> allowed = new ArrayList<>(0);
for (final XML method : clazz.nodes("methods/method")) {
final String name = method.xpath("@name").get(0);
if (isConstructorExcluded(params, method) || isStaticMethodExcluded(params, method)) {
continue;
}
allowed.add(method);
parents.put(name, name);
}
final UnionFind<String> find = new UnionFind<>(parents);
for (final XML method : allowed) {
final String name = method.xpath("@name").get(0);
final List<XML> ops = method.nodes("ops/op");
for (final XML operation : ops) {
final String code = operation.xpath("@code").get(0);
if (code.equals("call")) {
final String classpath = operation.nodes("name").get(0).node().getTextContent();
final List<String> splits = Arrays.asList(classpath.split("\\."));
if (parents.keySet().contains(splits.get(splits.size() - 1))) {
find.unite(name, splits.get(splits.size() - 1));
}
} else {
final String var = operation.node().getTextContent();
if (connections.containsKey(var)) {
connections.get(var).add(name);
} else {
final List<String> init = new ArrayList<>(0);
init.add(name);
connections.put(var, init);
}
}
}
private static XML findNcc(final XML skeleton, final XML meta) {
XML result = meta;
final XSL ncc = new XSLDocument(
XslReport.class.getResourceAsStream(
"xsl/meta/meta-ncc.xsl"
)
);
for (final XML clazz : meta.nodes("//class")) {
final XML pack = clazz.nodes("..").get(0);
final XmlGraph graph = new XmlGraph(
skeleton,
pack.xpath("@id").get(0),
clazz.xpath("@id").get(0)
);
final String size = String.valueOf(new Disjoint(graph).value().size());
result = ncc
.with("package", pack.xpath("@id").get(0))
.with("class", clazz.xpath("@id").get(0))
.with("value", size)
.transform(meta);
}
return connectNodes(find, connections);
return new XSLDocument(
XslReport.class.getResourceAsStream(
"xsl/meta/skeleton-appender.xsl"
)
).with("meta", result.node()).transform(skeleton);
}

/**
* Connects nodes and calculates the number of components.
* This method connects nodes based and calculates the number of components
* using the Union-Find algorithm.
* @param find The Union-Find data structure to manage node connections.
* @param connections A map containing the relationships between nodes.
* @return The number of components after connecting nodes.
* Adds an XSL filter to the list of layers.
*
* @param layers The list of XSL filters
* @param name The name of the XSL file to add
* @return The updated list of XSL filters
*/
private static int connectNodes(final UnionFind<String> find,
final Map<String, List<String>> connections
) {
connections.values().stream().forEach(
conns -> {
final String init = conns.get(0);
conns.stream().forEach(current -> find.unite(init, current));
}
private static List<XSL> addXslFilter(final List<XSL> layers, final String name) {
final XSLDocument doc = new XSLDocument(
XslReport.class.getResourceAsStream(String.format("xsl/layers/%s", name))
);
return find.getSize();
}

/**
* Checks if a static method should be excluded based on parameters.
* @param params Parameters for filtering.
* @param method The method XML node.
* @return True if the method should be excluded, false otherwise.
*/
private static boolean isStaticMethodExcluded(final Map<String, Object> params,
final XML method) {
return !params.containsKey("include-static-methods") && method.xpath("@static").get(0)
.equals("true");
}

/**
* Checks if a constructor should be excluded based on parameters.
* @param params Parameters for filtering.
* @param method The method XML node.
* @return True if the constructor should be excluded, false otherwise.
*/
private static boolean isConstructorExcluded(final Map<String, Object> params,
final XML method) {
return !params.containsKey("include-ctors") && method.xpath("@ctor").get(0).equals("true");
layers.add(doc);
return layers;
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/jpeek/graph/Disjoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public Disjoint(final Graph graph) {
}

@Override
public List<Set<Node>> value() throws Exception {
public List<Set<Node>> value() {
final Set<Node> unvisited = new HashSet<>(this.graph.nodes());
final List<Set<Node>> result = new ArrayList<>(unvisited.size());
while (!unvisited.isEmpty()) {
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/org/jpeek/graph/XmlGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.cactoos.scalar.Sticky;
import org.cactoos.scalar.Unchecked;
import org.cactoos.text.FormattedText;
import org.jpeek.skeleton.Skeleton;

/**
* Graph implementation built on skeleton.
Expand All @@ -54,7 +53,7 @@ public final class XmlGraph implements Graph {
* @param pname Package of the class this graph is for
* @param cname Class in the skeleton this graph is for
*/
public XmlGraph(final Skeleton skeleton, final String pname, final String cname) {
public XmlGraph(final XML skeleton, final String pname, final String cname) {
this.nds = new Unchecked<>(
new Sticky<>(
() -> XmlGraph.build(skeleton, pname, cname)
Expand All @@ -74,13 +73,13 @@ public List<Node> nodes() {
* @param cname Class in the skeleton this graph is for
* @return List of nodes
*/
private static List<Node> build(final Skeleton skeleton, final String pname,
private static List<Node> build(final XML skeleton, final String pname,
final String cname) {
final Map<XML, Node> byxml = new MapOf<>(
method -> method,
method -> new Node.Simple(
new XmlMethodSignature(
skeleton.xml()
skeleton
.nodes(
new FormattedText(
"//package[@id='%s']", pname
Expand All @@ -94,7 +93,7 @@ private static List<Node> build(final Skeleton skeleton, final String pname,
method
).asString()
),
skeleton.xml().nodes(
skeleton.nodes(
"//methods/method[@ctor='false' and @abstract='false']"
)
);
Expand Down
10 changes: 1 addition & 9 deletions src/main/resources/org/jpeek/metrics/CCM.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,12 @@ SOFTWARE.
<xsl:value-of select="$other/@name"/>
</method>
</edge>
<edge>
<method>
<xsl:value-of select="$other/@name"/>
</method>
<method>
<xsl:value-of select="$method/@name"/>
</method>
</edge>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:copy>
<xsl:variable name="nc" select="count($edges/edge) div 2"/>
<xsl:variable name="nc" select="count($edges/edge)"/>
<xsl:variable name="ncc" select="$currentClassNcc"/>
<xsl:variable name="nmp" select="(count($methods) * (count($methods) - 1)) div 2"/>
<xsl:attribute name="value">
Expand Down
23 changes: 23 additions & 0 deletions src/main/resources/org/jpeek/xsl/meta/meta-creater.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="skeleton" name="meta">
<meta>
<xsl:apply-templates select="descendant::package"/>
</meta>
</xsl:template>
<xsl:template match="package">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="class">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
22 changes: 22 additions & 0 deletions src/main/resources/org/jpeek/xsl/meta/meta-ncc.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<!-- Parameters -->
<xsl:param name="package"/>
<xsl:param name="class"/>
<xsl:param name="value"/>
<!-- Identity template: copies everything as is by default -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Template to add <ncc> tag inside <class> if package and class match parameters -->
<xsl:template match="package[@id=$package]//class[@id=$class]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<ncc>
<xsl:value-of select="$value"/>
</ncc>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
<?xml version="1.0"?>
<!--
The MIT License (MIT)
Copyright (c) 2017-2024 Yegor Bugayenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
Expand Down
Loading

0 comments on commit bb8e09f

Please sign in to comment.