Makes JCL compatibility report to be more usable

This commit is contained in:
konsoletyper 2014-03-06 10:47:20 +04:00
parent 43b41b3a66
commit da314bf6f2
12 changed files with 225 additions and 78 deletions

View File

@ -25,6 +25,8 @@ import java.util.List;
class JCLClass { class JCLClass {
public final String name; public final String name;
public JCLStatus status; public JCLStatus status;
public JCLVisibility visibility = JCLVisibility.PUBLIC;
public JCLClassType type;
public final List<JCLItem> items = new ArrayList<>(); public final List<JCLItem> items = new ArrayList<>();
public JCLClass(String name) { public JCLClass(String name) {

View File

@ -0,0 +1,27 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.impl;
/**
*
* @author Alexey Andreev
*/
enum JCLClassType {
CLASS,
INTERFACE,
ENUM,
ANNOTATION
}

View File

@ -87,10 +87,30 @@ public class JCLComparisonBuilder {
copyResource("html/methpro_obj.png"); copyResource("html/methpro_obj.png");
copyResource("html/methpub_obj.png"); copyResource("html/methpub_obj.png");
copyResource("html/package_obj.png"); copyResource("html/package_obj.png");
copyResource("html/int_obj.png");
copyResource("html/enum_obj.png");
try (Writer out = new OutputStreamWriter(new FileOutputStream(new File( try (Writer out = new OutputStreamWriter(new FileOutputStream(new File(
outputDirectory, "jcl.html")), "UTF-8")) { outputDirectory, "jcl.html")), "UTF-8")) {
generateHtml(out, packages); generateHtml(out, packages);
} }
File packagesDirectory = new File(outputDirectory, "packages");
packagesDirectory.mkdirs();
for (JCLPackage pkg : packages) {
File file = new File(packagesDirectory, pkg.name + ".html");
try (Writer out = new OutputStreamWriter(new FileOutputStream(file))) {
generatePackageHtml(out, pkg);
}
}
File classesDirectory = new File(outputDirectory, "classes");
classesDirectory.mkdirs();
for (JCLPackage pkg : packages) {
for (JCLClass cls : pkg.classes) {
File file = new File(classesDirectory, pkg.name + "." + cls.name + ".html");
try (Writer out = new OutputStreamWriter(new FileOutputStream(file))) {
generateClassHtml(out, pkg, cls);
}
}
}
} }
private List<JCLPackage> buildModel() throws IOException { private List<JCLPackage> buildModel() throws IOException {
@ -185,39 +205,108 @@ public class JCLComparisonBuilder {
break; break;
} }
} }
writeRow(out, "package", pkg.status, pkg.name, writeRow(out, "package", "packages/" + pkg.name + ".html", pkg.status, pkg.name,
totalClasses > 0 ? fullClasses * 100 / totalClasses : null, totalClasses > 0 ? fullClasses * 100 / totalClasses : null,
totalClasses > 0 ? partialClasses * 100 / totalClasses : null); totalClasses > 0 ? partialClasses * 100 / totalClasses : null);
for (JCLClass cls : pkg.classes) {
int implemented = 0;
for (JCLItem item : cls.items) {
if (item.status != JCLStatus.MISSING) {
++implemented;
}
}
writeRow(out, "class", cls.status, cls.name,
!cls.items.isEmpty() ? implemented * 100 / cls.items.size() : null, null);
for (JCLItem item : cls.items) {
String type;
switch (item.type) {
case FIELD:
type = "field";
break;
case METHOD:
type = "method";
break;
default:
type = "";
break;
}
writeRow(out, type, item.status, item.name, null, null);
}
}
} }
out.write(footer); out.write(footer);
} }
private void writeRow(Writer out, String type, JCLStatus status, String name, Integer percent, private void generatePackageHtml(Writer out, JCLPackage pkg) throws IOException {
String template;
try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream("html/jcl-class.html"), "UTF-8")) {
template = IOUtils.toString(reader);
}
template = template.replace("${CLASSNAME}", pkg.name);
int placeholderIndex = template.indexOf(TEMPLATE_PLACEHOLDER);
String header = template.substring(0, placeholderIndex);
String footer = template.substring(placeholderIndex + TEMPLATE_PLACEHOLDER.length());
out.write(header);
int totalClasses = pkg.classes.size();
int fullClasses = 0;
int partialClasses = 0;
for (JCLClass cls : pkg.classes) {
switch (cls.status) {
case FOUND:
fullClasses++;
partialClasses++;
break;
case PARTIAL:
partialClasses++;
break;
default:
break;
}
}
writeRow(out, "package", null, pkg.status, pkg.name,
totalClasses > 0 ? fullClasses * 100 / totalClasses : null,
totalClasses > 0 ? partialClasses * 100 / totalClasses : null);
for (JCLClass cls : pkg.classes) {
writeClassRow(out, pkg, cls);
}
out.write(footer);
}
private void generateClassHtml(Writer out, JCLPackage pkg, JCLClass cls) throws IOException {
String template;
try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream("html/jcl-class.html"), "UTF-8")) {
template = IOUtils.toString(reader);
}
template = template.replace("${CLASSNAME}", pkg.name + "." + cls.name);
int placeholderIndex = template.indexOf(TEMPLATE_PLACEHOLDER);
String header = template.substring(0, placeholderIndex);
String footer = template.substring(placeholderIndex + TEMPLATE_PLACEHOLDER.length());
out.write(header);
writeRow(out, "package", null, pkg.status, pkg.name, null, null);
writeClassRow(out, pkg, cls);
for (JCLItem item : cls.items) {
String type;
switch (item.type) {
case FIELD:
type = "field";
break;
case METHOD:
type = "method";
break;
default:
type = "";
break;
}
if (item.visibility == JCLVisibility.PROTECTED) {
type = "protected " + type;
}
writeRow(out, type, null, item.status, item.name, null, null);
}
out.write(footer);
}
private void writeClassRow(Writer out, JCLPackage pkg, JCLClass cls) throws IOException {
int implemented = 0;
for (JCLItem item : cls.items) {
if (item.status != JCLStatus.MISSING) {
++implemented;
}
}
String type;
switch (cls.type) {
case INTERFACE:
type = "interface";
break;
case ANNOTATION:
type = "annotation";
break;
case ENUM:
type = "enum";
break;
default:
type = "class";
break;
}
writeRow(out, type + " type", "../classes/" + pkg.name + "." + cls.name + ".html", cls.status, cls.name,
!cls.items.isEmpty() ? implemented * 100 / cls.items.size() : null, null);
}
private void writeRow(Writer out, String type, String link, JCLStatus status, String name, Integer percent,
Integer partialPercent) throws IOException { Integer partialPercent) throws IOException {
out.write("<tr class=\""); out.write("<tr class=\"");
switch (status) { switch (status) {
@ -235,7 +324,13 @@ public class JCLComparisonBuilder {
out.write("<td><div class=\""); out.write("<td><div class=\"");
out.write(type); out.write(type);
out.write("\">"); out.write("\">");
if (link != null) {
out.write("<a href=\"" + link + "\">");
}
out.write(escape(name)); out.write(escape(name));
if (link != null) {
out.write("</a>");
}
out.write("</div></td>\n"); out.write("</div></td>\n");
out.write("<td class=\"percent\">" + (partialPercent != null ? partialPercent.toString() : "") + "</td>"); out.write("<td class=\"percent\">" + (partialPercent != null ? partialPercent.toString() : "") + "</td>");
out.write("<td class=\"percent\">" + (percent != null ? percent.toString() : "") + "</td>"); out.write("<td class=\"percent\">" + (percent != null ? percent.toString() : "") + "</td>");

View File

@ -56,6 +56,16 @@ class JCLComparisonVisitor implements ClassVisitor {
classReader = classSource.get(javaName); classReader = classSource.get(javaName);
jclClass = new JCLClass(simpleName); jclClass = new JCLClass(simpleName);
jclClass.status = classReader != null ? JCLStatus.FOUND : JCLStatus.MISSING; jclClass.status = classReader != null ? JCLStatus.FOUND : JCLStatus.MISSING;
jclClass.visibility = (access & Opcodes.ACC_PROTECTED) != 0 ? JCLVisibility.PROTECTED : JCLVisibility.PUBLIC;
if ((access & Opcodes.ACC_INTERFACE) != 0) {
jclClass.type = JCLClassType.INTERFACE;
} else if ((access & Opcodes.ACC_ANNOTATION) != 0) {
jclClass.type = JCLClassType.ANNOTATION;
} else if ((access & Opcodes.ACC_ENUM) != 0) {
jclClass.type = JCLClassType.ENUM;
} else {
jclClass.type = JCLClassType.CLASS;
}
jclPackage.classes.add(jclClass); jclPackage.classes.add(jclClass);
} }
@ -67,6 +77,7 @@ class JCLComparisonVisitor implements ClassVisitor {
JCLItem item = new JCLItem(JCLItemType.FIELD, name + " : " + desc); JCLItem item = new JCLItem(JCLItemType.FIELD, name + " : " + desc);
FieldReader field = classReader.getField(name); FieldReader field = classReader.getField(name);
item.status = field != null ? JCLStatus.FOUND : JCLStatus.MISSING; item.status = field != null ? JCLStatus.FOUND : JCLStatus.MISSING;
item.visibility = (access & Opcodes.ACC_PROTECTED) != 0 ? JCLVisibility.PROTECTED : JCLVisibility.PUBLIC;
jclClass.items.add(item); jclClass.items.add(item);
if (item.status == JCLStatus.MISSING) { if (item.status == JCLStatus.MISSING) {
jclClass.status = JCLStatus.PARTIAL; jclClass.status = JCLStatus.PARTIAL;
@ -92,6 +103,7 @@ class JCLComparisonVisitor implements ClassVisitor {
JCLStatus.FOUND : JCLStatus.PARTIAL; JCLStatus.FOUND : JCLStatus.PARTIAL;
} }
} }
item.visibility = (access & Opcodes.ACC_PROTECTED) != 0 ? JCLVisibility.PROTECTED : JCLVisibility.PUBLIC;
jclClass.items.add(item); jclClass.items.add(item);
if (item.status == JCLStatus.MISSING) { if (item.status == JCLStatus.MISSING) {
jclClass.status = JCLStatus.PARTIAL; jclClass.status = JCLStatus.PARTIAL;

View File

@ -22,6 +22,7 @@ package org.teavm.classlib.impl;
class JCLItem { class JCLItem {
public final JCLItemType type; public final JCLItemType type;
public final String name; public final String name;
public JCLVisibility visibility = JCLVisibility.PUBLIC;
public JCLStatus status; public JCLStatus status;
public JCLItem(JCLItemType type, String name) { public JCLItem(JCLItemType type, String name) {

View File

@ -0,0 +1,25 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.impl;
/**
*
* @author Alexey Andreev
*/
enum JCLVisibility {
PUBLIC,
PROTECTED
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>JCL emulation information - ${CLASSNAME}</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="stylesheet" href="../jcl.css" type="text/css"/>
</head>
<body>
<table>
<thead>
<tr>
<th>Item</th>
<th>% of partially implemented</th>
<th>% of fully implemented</th>
</tr>
</thead>
<tbody>
${CONTENT}
</tbody>
</table>
</body>
</html>

View File

@ -1,46 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>JCL emulation information</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="stylesheet" href="jcl.css" type="text/css"/>
</head>
<body>
<table>
<thead>
<tr>
<th>Item</th>
<th>% of partially implemented</th>
<th>% of fully implemented</th>
</tr>
</thead>
<tbody>
<tr class="full">
<td><div class="package">java.lang</div></td>
<td class="percent">100%</td>
<td class="percent">0%</td>
</tr>
<tr class="partial">
<td><div class="class">Object</div></td>
<td class="percent"></td>
<td class="percent">50%</td>
</tr>
<tr class="full">
<td><div class="field">$id</div></td>
<td class="percent"></td>
<td class="percent"></td>
</tr>
<tr class="full">
<td><div class="method">clone()</div></td>
<td></td>
<td></td>
</tr>
<tr class="missing">
<td><div class="method">getClass()</div></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -36,7 +36,7 @@ th {
text-align: right; text-align: right;
} }
.package, .class, .protected-class, .field, .protected-field, .method, .protected-method { .package, .type, .field, .method {
background-repeat: no-repeat; background-repeat: no-repeat;
padding-right: 6px; padding-right: 6px;
} }
@ -45,11 +45,11 @@ th {
padding-left: 35px; padding-left: 35px;
background-position: 16px 50%; background-position: 16px 50%;
} }
.class { .type {
padding-left: 51px; padding-left: 51px;
background-position: 32px 50%; background-position: 32px 50%;
} }
.field, .protected-field, .method, .protected-method { .field, .method {
padding-left: 67px; padding-left: 67px;
background-position: 48px 50%; background-position: 48px 50%;
} }
@ -60,15 +60,24 @@ th {
.class { .class {
background-image: url(class_obj.png); background-image: url(class_obj.png);
} }
.annotation {
background-image: url(annotation_obj.png);
}
.interface {
background-image: url(int_obj.png);
}
.enum {
background-image: url(enum_obj.png);
}
.field { .field {
background-image: url(field_public_obj.png); background-image: url(field_public_obj.png);
} }
.protected-field { .protected.field {
background-image: url(field_protected_obj.png); background-image: url(field_protected_obj.png);
} }
.method { .method {
background-image: url(methpub_obj.png); background-image: url(methpub_obj.png);
} }
.protected-method { .protected.method {
background-image: url(methpro_obj.png); background-image: url(methpro_obj.png);
} }