blob: 874d1a08b9a5cf6277fec4de664318951cb92e83 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.api.tools.internal.search;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.Signature;
import org.eclipse.osgi.util.NLS;
import org.eclipse.osgi.util.TextProcessor;
import org.eclipse.pde.api.tools.internal.IApiXmlConstants;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IFieldDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMethodDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.search.IMetadata;
import org.eclipse.pde.api.tools.internal.util.Signatures;
import org.eclipse.pde.api.tools.internal.util.Util;
import org.osgi.framework.Version;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* This class converts a collection of API use report XML files from a given
* location to a corresponding collection of HTML in a given location
*
* @since 1.0.1
*/
public class UseReportConverter extends HTMLConvertor {
/**
* Use visitor to write the reports
*/
class Visitor extends UseScanVisitor {
ArrayList<Report> reports = new ArrayList<>();
Report currentreport = null;
Type currenttype = null, currentreferee = null;
Member currentmember = null;
HashMap<IReferenceTypeDescriptor, Type> keys = new HashMap<>();
ArrayList<Type> referees = new ArrayList<>();
/**
* Returns if the reference should be reported or not
*
* @param desc
* @return true if the reference should be reported false otherwise
*/
private boolean acceptReference(IMemberDescriptor desc, Pattern[] patterns) {
if (patterns != null) {
for (Pattern pattern : patterns) {
if (pattern.matcher(desc.getPackage().getName()).find()) {
return false;
}
}
}
return true;
}
/**
* Returns the enclosing {@link IReferenceTypeDescriptor} for the given
* member descriptor
*
* @param member
* @return the enclosing {@link IReferenceTypeDescriptor} or
* <code>null</code>
*/
IReferenceTypeDescriptor getEnclosingDescriptor(IMemberDescriptor member) {
switch (member.getElementType()) {
case IElementDescriptor.TYPE: {
return (IReferenceTypeDescriptor) member;
}
case IElementDescriptor.METHOD:
case IElementDescriptor.FIELD: {
return member.getEnclosingType();
}
default:
break;
}
return null;
}
@Override
public boolean visitComponent(IComponentDescriptor target) {
this.currentreport = new Report();
this.currentreport.name = composeName(target.getId(), target.getVersion());
this.reports.add(this.currentreport);
return true;
}
@Override
public void endVisitComponent(IComponentDescriptor target) {
try {
long start = 0;
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println("Writing report for bundle: " + target.getId()); //$NON-NLS-1$
start = System.currentTimeMillis();
}
if (this.currentreport.counts.getTotalRefCount() > 0) {
writeReferencedMemberPage(this.currentreport, this.referees);
} else {
this.reports.remove(this.currentreport);
}
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println("done in: " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
} catch (Exception e) {
ApiPlugin.log(e);
} finally {
// clear any children as we have written them out - keep the
// report object to write a sorted index page
this.currentreport.children.clear();
this.keys.clear();
this.referees.clear();
}
}
@Override
public boolean visitReferencingComponent(IComponentDescriptor component) {
this.currentreferee = new Type(component);
return true;
}
@Override
public void endVisitReferencingComponent(IComponentDescriptor component) {
if (this.currentreferee.counts.getTotalRefCount() > 0) {
this.referees.add(this.currentreferee);
}
}
@Override
public boolean visitMember(IMemberDescriptor referencedMember) {
IReferenceTypeDescriptor desc = getEnclosingDescriptor(referencedMember);
if (desc == null) {
return false;
}
this.currenttype = this.keys.get(desc);
if (this.currenttype == null) {
this.currenttype = new Type(desc);
this.keys.put(desc, this.currenttype);
}
TreeMap<IMemberDescriptor, Member> map = this.currentreport.children.get(this.currenttype);
if (map == null) {
map = new TreeMap<>(compare);
this.currentreport.children.put(this.currenttype, map);
}
this.currentmember = map.get(referencedMember);
if (this.currentmember == null) {
this.currentmember = new Member(referencedMember);
map.put(referencedMember, this.currentmember);
}
return true;
}
@Override
public void endVisitMember(IMemberDescriptor referencedMember) {
if (this.currentmember.children.isEmpty()) {
TreeMap<IMemberDescriptor, Member> map = this.currentreport.children.get(this.currenttype);
map.remove(referencedMember);
}
if (this.currenttype.counts.getTotalRefCount() == 0) {
IReferenceTypeDescriptor desc = getEnclosingDescriptor(referencedMember);
if (desc != null) {
this.keys.remove(desc);
this.currentreport.children.remove(this.currenttype);
}
}
}
/**
* Formats the arrays of messages
*
* @param messages
* @return the formatted messages or <code>null</code>
*/
String formatMessages(String[] messages) {
if (messages != null) {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < messages.length; i++) {
buffer.append(messages[i]);
if (i < messages.length - 1) {
buffer.append("\n"); //$NON-NLS-1$
}
}
return buffer.toString();
}
return null;
}
@Override
public void visitReference(IReferenceDescriptor reference) {
IMemberDescriptor fromMember = reference.getMember();
if (!acceptReference(reference.getReferencedMember(), topatterns) || !acceptReference(fromMember, frompatterns)) {
return;
}
int lineNumber = reference.getLineNumber();
int refKind = reference.getReferenceKind();
int visibility = reference.getVisibility();
String refname = org.eclipse.pde.api.tools.internal.builder.Reference.getReferenceText(refKind);
List<Reference> refs = this.currentmember.children.get(refname);
if (refs == null) {
refs = new ArrayList<>();
this.currentmember.children.put(refname, refs);
}
refs.add(new Reference(fromMember, lineNumber, visibility, formatMessages(reference.getProblemMessages())));
switch (fromMember.getElementType()) {
case IElementDescriptor.TYPE: {
switch (visibility) {
case VisibilityModifiers.API: {
this.currentmember.counts.total_api_type_count++;
this.currenttype.counts.total_api_type_count++;
this.currentreferee.counts.total_api_type_count++;
this.currentreport.counts.total_api_type_count++;
break;
}
case VisibilityModifiers.PRIVATE: {
this.currentmember.counts.total_private_type_count++;
this.currenttype.counts.total_private_type_count++;
this.currentreferee.counts.total_private_type_count++;
this.currentreport.counts.total_private_type_count++;
break;
}
case VisibilityModifiers.PRIVATE_PERMISSIBLE: {
this.currentmember.counts.total_permissable_type_count++;
this.currenttype.counts.total_permissable_type_count++;
this.currentreferee.counts.total_permissable_type_count++;
this.currentreport.counts.total_permissable_type_count++;
break;
}
case FRAGMENT_PERMISSIBLE: {
this.currentmember.counts.total_fragment_permissible_type_count++;
this.currenttype.counts.total_fragment_permissible_type_count++;
this.currentreferee.counts.total_fragment_permissible_type_count++;
this.currentreport.counts.total_fragment_permissible_type_count++;
break;
}
case VisibilityModifiers.ILLEGAL_API: {
this.currentmember.counts.total_illegal_type_count++;
this.currenttype.counts.total_illegal_type_count++;
this.currentreferee.counts.total_illegal_type_count++;
this.currentreport.counts.total_illegal_type_count++;
break;
}
default:
break;
}
break;
}
case IElementDescriptor.METHOD: {
switch (visibility) {
case VisibilityModifiers.API: {
this.currentmember.counts.total_api_method_count++;
this.currenttype.counts.total_api_method_count++;
this.currentreferee.counts.total_api_method_count++;
this.currentreport.counts.total_api_method_count++;
break;
}
case VisibilityModifiers.PRIVATE: {
this.currentmember.counts.total_private_method_count++;
this.currenttype.counts.total_private_method_count++;
this.currentreferee.counts.total_private_method_count++;
this.currentreport.counts.total_private_method_count++;
break;
}
case VisibilityModifiers.PRIVATE_PERMISSIBLE: {
this.currentmember.counts.total_permissable_method_count++;
this.currenttype.counts.total_permissable_method_count++;
this.currentreferee.counts.total_permissable_method_count++;
this.currentreport.counts.total_permissable_method_count++;
break;
}
case FRAGMENT_PERMISSIBLE: {
this.currentmember.counts.total_fragment_permissible_method_count++;
this.currenttype.counts.total_fragment_permissible_method_count++;
this.currentreferee.counts.total_fragment_permissible_method_count++;
this.currentreport.counts.total_fragment_permissible_method_count++;
break;
}
case VisibilityModifiers.ILLEGAL_API: {
this.currentmember.counts.total_illegal_method_count++;
this.currenttype.counts.total_illegal_method_count++;
this.currentreferee.counts.total_illegal_method_count++;
this.currentreport.counts.total_illegal_method_count++;
break;
}
default:
break;
}
break;
}
case IElementDescriptor.FIELD: {
switch (visibility) {
case VisibilityModifiers.API: {
this.currentmember.counts.total_api_field_count++;
this.currenttype.counts.total_api_field_count++;
this.currentreferee.counts.total_api_field_count++;
this.currentreport.counts.total_api_field_count++;
break;
}
case VisibilityModifiers.PRIVATE: {
this.currentmember.counts.total_private_field_count++;
this.currenttype.counts.total_private_field_count++;
this.currentreferee.counts.total_private_field_count++;
this.currentreport.counts.total_private_field_count++;
break;
}
case VisibilityModifiers.PRIVATE_PERMISSIBLE: {
this.currentmember.counts.total_permissable_field_count++;
this.currenttype.counts.total_permissable_field_count++;
this.currentreferee.counts.total_permissable_field_count++;
this.currentreport.counts.total_permissable_field_count++;
break;
}
case FRAGMENT_PERMISSIBLE: {
this.currentmember.counts.total_fragment_permissible_field_count++;
this.currenttype.counts.total_fragment_permissible_field_count++;
this.currentreferee.counts.total_fragment_permissible_field_count++;
this.currentreport.counts.total_fragment_permissible_field_count++;
break;
}
case VisibilityModifiers.ILLEGAL_API: {
this.currentmember.counts.total_illegal_field_count++;
this.currenttype.counts.total_illegal_field_count++;
this.currentreferee.counts.total_illegal_field_count++;
this.currentreport.counts.total_illegal_field_count++;
break;
}
default:
break;
}
break;
}
default:
break;
}
}
}
/**
* Comparator for use report items
*/
static Comparator<Object> compare = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof String && o2 instanceof String) {
return ((String) o1).compareTo((String) o2);
}
if (o1 instanceof Type && o2 instanceof Type) {
return compare(((Type) o1).desc, ((Type) o2).desc);
}
if (o1 instanceof IReferenceTypeDescriptor && o2 instanceof IReferenceTypeDescriptor) {
return ((IReferenceTypeDescriptor) o1).getQualifiedName().compareTo(((IReferenceTypeDescriptor) o2).getQualifiedName());
}
if (o1 instanceof IMethodDescriptor && o2 instanceof IMethodDescriptor) {
try {
return Signatures.getQualifiedMethodSignature((IMethodDescriptor) o1).compareTo(Signatures.getQualifiedMethodSignature((IMethodDescriptor) o2));
} catch (CoreException ce) {
return -1;
}
}
if (o1 instanceof IFieldDescriptor && o2 instanceof IFieldDescriptor) {
return Signatures.getQualifiedFieldSignature((IFieldDescriptor) o1).compareTo(Signatures.getQualifiedFieldSignature((IFieldDescriptor) o2));
}
if (o1 instanceof IComponentDescriptor && o2 instanceof IComponentDescriptor) {
return ((IComponentDescriptor) o1).getId().compareTo(((IComponentDescriptor) o2).getId());
}
return -1;
}
};
/**
* Root item describing the use of one component
*/
static class Report {
String name = null;
TreeMap<Type, TreeMap<IMemberDescriptor, Member>> children = new TreeMap<>(compare);
CountGroup counts = new CountGroup();
}
/**
* Describes a type, used to key a collection of {@link Member}s
*/
static class Type {
IElementDescriptor desc = null;
CountGroup counts = new CountGroup();
public Type(IElementDescriptor desc) {
this.desc = desc;
}
}
/**
* Describes a member that is being used
*/
static class Member {
IElementDescriptor descriptor = null;
TreeMap<String, List<Reference>> children = new TreeMap<>(compare);
CountGroup counts = new CountGroup();
public Member(IElementDescriptor desc) {
this.descriptor = desc;
}
}
/**
* Describes a reference from a given descriptor
*/
static class Reference {
IElementDescriptor desc = null;
int line = -1, vis = -1;
String message = null;
public Reference(IElementDescriptor desc, int line, int vis, String message) {
this.desc = desc;
this.line = line;
this.vis = vis;
this.message = message;
}
}
/**
* A group of counters to origin meta-data
*/
static final class CountGroup {
int total_api_field_count = 0;
int total_private_field_count = 0;
int total_permissable_field_count = 0;
int total_fragment_permissible_field_count = 0;
int total_illegal_field_count = 0;
int total_api_method_count = 0;
int total_private_method_count = 0;
int total_permissable_method_count = 0;
int total_fragment_permissible_method_count = 0;
int total_illegal_method_count = 0;
int total_api_type_count = 0;
int total_private_type_count = 0;
int total_permissable_type_count = 0;
int total_fragment_permissible_type_count = 0;
int total_illegal_type_count = 0;
public int getTotalRefCount() {
return total_api_field_count + total_api_method_count + total_api_type_count + total_private_field_count + total_private_method_count + total_private_type_count + total_permissable_field_count + total_permissable_method_count + total_permissable_type_count + total_fragment_permissible_field_count + total_fragment_permissible_method_count + total_fragment_permissible_type_count + total_illegal_field_count + total_illegal_method_count + total_illegal_type_count;
}
public int getTotalApiRefCount() {
return total_api_field_count + total_api_method_count + total_api_type_count;
}
public int getTotalInternalRefCount() {
return total_private_field_count + total_private_method_count + total_private_type_count;
}
public int getTotalPermissableRefCount() {
return total_permissable_field_count + total_permissable_method_count + total_permissable_type_count;
}
public int getTotalFragmentPermissibleRefCount() {
return total_fragment_permissible_field_count + total_fragment_permissible_method_count + total_fragment_permissible_type_count;
}
public int getTotalIllegalRefCount() {
return total_illegal_field_count + total_illegal_method_count + total_illegal_type_count;
}
}
/**
* Handler for parsing the not_searched.xml file to output a summary or
* missing required bundles
*/
static final class MissingHandler extends DefaultHandler {
List<String> missing = new ArrayList<>();
static String pattern = "Require-Bundle:"; //$NON-NLS-1$
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (IApiXmlConstants.ELEMENT_COMPONENT.equals(qName)) {
String value = attributes.getValue("details"); //$NON-NLS-1$
StringTokenizer tokenizer = new StringTokenizer(value, "<>"); //$NON-NLS-1$
int index = -1;
while (tokenizer.hasMoreTokens()) {
value = tokenizer.nextToken();
index = value.indexOf(pattern);
if (index > -1) {
missing.add(value.replaceAll(pattern, Util.EMPTY_STRING));
}
}
}
}
}
/**
* Visibility constant indicating an element has host-fragment level of
* visibility. i.e. fragments have {@link #PRIVATE_PERMISSIBLE}-like access
* to the internals of their host.
*
* @since 1.0.1
*/
public static final int FRAGMENT_PERMISSIBLE = 0x0000005;
/**
* Default XSLT file name
*/
public static final String DEFAULT_XSLT = "/references.xsl"; //$NON-NLS-1$
/**
* Colour white for normal / permissible references Possibility: #C0E0C0
*/
public static final String NORMAL_REFS_COLOUR = "#FFFFFF"; //$NON-NLS-1$
/**
* Colour red for internal references Old colour: #E0A0A0
*/
public static final String INTERNAL_REFS_COLOUR = "#F2C3C3"; //$NON-NLS-1$
/**
* Colour gray for illegal references
*
* @since 1.1
*/
public static final String ILLEGAL_REFS_COLOUR = "#E0E0E0"; //$NON-NLS-1$
/**
* Colour gold for the references table header. Old colour: #CC9933
*
* @since 1.1
*/
public static final String REFERENCES_TABLE_HEADER_COLOUR = "#E0C040"; //$NON-NLS-1$
/**
* Style HTML bits for a page that shows references
*/
static final String REF_STYLE;
/**
* The script block used to show an expanding table of references
*/
static final String REF_SCRIPT;
static {
StringBuilder buffer = new StringBuilder();
buffer.append("<style type=\"text/css\">\n"); //$NON-NLS-1$
buffer.append("\t.main {\t\tfont-family:Arial, Helvetica, sans-serif;\n\t}\n"); //$NON-NLS-1$
buffer.append("\t.main h3 {\n\t\tfont-family:Arial, Helvetica, sans-serif;\n\t\t\background-color:#FFFFFF;\n\t\tfont-size:14px;\n\t\tmargin:0.1em;\n\t}\n"); //$NON-NLS-1$
buffer.append("\t.main h4 {\n\t\tbackground-color:#CCCCCC;\n\t\tmargin:0.15em;\n\t}\n"); //$NON-NLS-1$
buffer.append("\ta.typeslnk {\n\t\tfont-family:Arial, Helvetica, sans-serif;\n\t\ttext-decoration:none;\n\t\tmargin-left:0.25em;\n\t}\n"); //$NON-NLS-1$
buffer.append("\ta.typeslnk:hover {\n\t\ttext-decoration:underline;\n\t}\n"); //$NON-NLS-1$
buffer.append("\ta.kindslnk {\n\t\tfont-family:Arial, Helvetica, sans-serif;\n\t\ttext-decoration:none;\n\t\tmargin-left:0.25em;\n\t}\n"); //$NON-NLS-1$
buffer.append("\t.types {\n\t\tdisplay:none;\n\t\tmargin-bottom:0.25em;\n\t\tmargin-top:0.25em;\n\t\tmargin-right:0.25em;\n\t\tmargin-left:0.75em;\n\t}\n"); //$NON-NLS-1$
buffer.append("</style>\n"); //$NON-NLS-1$
REF_STYLE = buffer.toString();
buffer = new StringBuilder();
buffer.append("<script type=\"text/javascript\">\n\tfunction expand(location) {\n\t\tif(document.getElementById) {\n\t\t\tvar childhtml = location.firstChild;\n\t\t\tif(!childhtml.innerHTML) {\n\t\t\t\tchildhtml = childhtml.nextSibling;\n\t\t\t}\n\t\t\tchildhtml.innerHTML = childhtml.innerHTML == '[+] ' ? '[-] ' : '[+] ';\n\t\t\tvar parent = location.parentNode;\n\t\t\tchildhtml = parent.nextSibling.style ? parent.nextSibling : parent.nextSibling.nextSibling;\n\t\t\tchildhtml.style.display = childhtml.style.display == 'block' ? 'none' : 'block';\n\t\t}\n\t}\n</script>\n"); //$NON-NLS-1$
buffer.append("<noscript>\n\t<style type=\"text/css\">\n\t\t.types {display:block;}\n\t\t.kinds{display:block;}\n\t</style>\n</noscript>\n"); //$NON-NLS-1$
REF_SCRIPT = buffer.toString();
}
private String xmlLocation = null;
private String htmlLocation = null;
private File reportsRoot = null;
private File htmlIndex = null;
private boolean hasmissing = false;
private boolean useNotSearchedXml = false;
SAXParser parser = null;
private UseMetadata metadata = null;
private int filteredCount = -1;
Pattern[] topatterns = null;
Pattern[] frompatterns = null;
/**
* Constructor
*
* @param htmlroot the folder root where the HTML reports should be written
* @param xmlroot the folder root where the current API use scan output is
* located
* @param topatterns array of regular expressions used to prune references
* to a given name pattern
* @param frompatterns array of regular expressions used to prune references
* from a given name pattern
*/
public UseReportConverter(String htmlroot, String xmlroot, String[] topatterns, String[] frompatterns) {
this.xmlLocation = xmlroot;
this.htmlLocation = htmlroot;
if (topatterns != null) {
ArrayList<Pattern> pats = new ArrayList<>(topatterns.length);
for (String topattern : topatterns) {
try {
pats.add(Pattern.compile(topattern));
} catch (PatternSyntaxException pse) {
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println(NLS.bind(SearchMessages.UseReportConverter_filter_pattern_not_valid, topattern));
System.out.println(pse.getMessage());
}
}
}
if (!pats.isEmpty()) {
this.topatterns = pats.toArray(new Pattern[pats.size()]);
}
}
if (frompatterns != null) {
ArrayList<Pattern> pats = new ArrayList<>(frompatterns.length);
for (String frompattern : frompatterns) {
try {
pats.add(Pattern.compile(frompattern));
} catch (PatternSyntaxException pse) {
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println(NLS.bind(SearchMessages.UseReportConverter_filter_pattern_not_valid, frompattern));
System.out.println(pse.getMessage());
}
}
}
if (!pats.isEmpty()) {
this.frompatterns = pats.toArray(new Pattern[pats.size()]);
}
}
}
protected String getHtmlLocation() {
return this.htmlLocation;
}
protected String getXmlLocation() {
return this.xmlLocation;
}
protected File getReportsRoot() {
if (this.reportsRoot == null) {
this.reportsRoot = new File(getXmlLocation());
}
return this.reportsRoot;
}
protected boolean hasMissing() {
return this.hasmissing;
}
/**
* Runs the converter on the given locations
*/
public void convert(String xslt, IProgressMonitor monitor) throws Exception {
if (getHtmlLocation() == null) {
return;
}
SubMonitor localmonitor = SubMonitor.convert(monitor, SearchMessages.UseReportConverter_preparing_report_metadata, 11);
try {
localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_html_root);
localmonitor.split(1);
File htmlRoot = new File(getHtmlLocation());
if (!htmlRoot.exists()) {
if (!htmlRoot.mkdirs()) {
throw new Exception(NLS.bind(SearchMessages.could_not_create_file, getHtmlLocation()));
}
} else {
htmlRoot.mkdirs();
}
localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_xml_root);
localmonitor.split(1);
if (getXmlLocation() == null) {
throw new Exception(SearchMessages.missing_xml_files_location);
}
File lreportsRoot = getReportsRoot();
if (!lreportsRoot.exists() || !lreportsRoot.isDirectory()) {
throw new Exception(NLS.bind(SearchMessages.invalid_directory_name, getXmlLocation()));
}
localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_xslt_file);
localmonitor.split(1);
File xsltFile = null;
if (xslt != null) {
// we will use the default XSLT transform from the ant jar when
// this is null
xsltFile = new File(xslt);
if (!xsltFile.exists() || !xsltFile.isFile()) {
throw new Exception(SearchMessages.UseReportConverter_xslt_file_not_valid);
}
}
long start = 0;
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
start = System.currentTimeMillis();
}
localmonitor.setTaskName(SearchMessages.UseReportConverter_writing_not_searched);
this.hasmissing = writeMissingBundlesPage(htmlRoot);
writeNotSearchedPage(htmlRoot);
localmonitor.split(1);
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println("done in: " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println("Parsing use scan..."); //$NON-NLS-1$
start = System.currentTimeMillis();
}
localmonitor.setTaskName(SearchMessages.UseReportConverter_parsing_use_scan);
List<?> result = parse(localmonitor.split(5));
localmonitor.split(1);
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println("done in: " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println("Sorting reports and writing index..."); //$NON-NLS-1$
start = System.currentTimeMillis();
}
localmonitor.setTaskName(SearchMessages.UseReportConverter_writing_root_index);
writeIndexPage(result);
localmonitor.split(1);
if (ApiPlugin.DEBUG_USE_REPORT_CONVERTER) {
System.out.println("done in: " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
writeMetaPage(htmlRoot);
} finally {
if (localmonitor != null) {
localmonitor.done();
}
}
}
protected List<?> parse(IProgressMonitor monitor) throws Exception {
UseScanParser lparser = new UseScanParser();
Visitor convertor = new Visitor();
lparser.parse(getXmlLocation(), monitor, convertor);
return convertor.reports;
}
/**
* Returns the handle to the default parser, caches the handle once it has
* been created
*
* @return the handle to the default parser
* @throws Exception forwarded general exception that can be trapped in Ant
* builds
*/
SAXParser getParser() throws Exception {
if (this.parser == null) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
this.parser = factory.newSAXParser();
} catch (ParserConfigurationException pce) {
throw new Exception(SearchMessages.UseReportConverter_pce_error_getting_parser, pce);
} catch (SAXException se) {
throw new Exception(SearchMessages.UseReportConverter_se_error_parser_handle, se);
}
if (this.parser == null) {
throw new Exception(SearchMessages.could_not_create_sax_parser);
}
}
return this.parser;
}
/**
* Builds the name for the component
*
* @param id id of the component
* @param version version of the component, can be <code>null</code>
* @return string name
*/
protected String composeName(String id, String version) {
String versionName = version;
if (version == null) {
versionName = Version.emptyVersion.toString();
}
StringBuilder buffer = new StringBuilder(3 + id.length() + versionName.length());
buffer.append(id).append(" (").append(versionName).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
return buffer.toString();
}
/**
* @return the index.html file created from the report conversion or
* <code>null</code> if the conversion failed
*/
public File getReportIndex() {
return htmlIndex;
}
protected void setReportIndex(File index) {
htmlIndex = index;
}
/**
* Applies the given XSLT to the given XML to produce HTML in the given file
*
* @param xsltfile
* @param xmlfile
* @param htmloutput
* @throws TransformerException
*/
protected void applyXSLT(File xsltFile, File xmlfile, File htmloutput) throws TransformerException, Exception {
Source xslt = null;
if (xsltFile != null) {
xslt = new StreamSource(xsltFile);
} else {
InputStream defaultXsltInputStream = UseReportConverter.class.getResourceAsStream(DEFAULT_XSLT);
if (defaultXsltInputStream != null) {
xslt = new StreamSource(new BufferedInputStream(defaultXsltInputStream));
}
}
if (xslt == null) {
throw new Exception(SearchMessages.UseReportConverter_no_xstl_specified);
}
applyXSLT(xslt, xmlfile, htmloutput);
}
/**
* Applies the given XSLT source to the given XML file outputting to the
* given HTML file
*
* @param xslt
* @param xmlfile
* @param htmlfile
* @throws TransformerException
*/
protected void applyXSLT(Source xslt, File xmlfile, File htmlfile) throws TransformerException {
Source xml = new StreamSource(xmlfile);
Result html = new StreamResult(htmlfile);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer former = factory.newTransformer(xslt);
former.transform(xml, html);
}
/**
* Transforms the given set of xml files with the given XSLT and places the
* result into a corresponding HTML file
*
* @param xmlfiles
* @param xsltFile
* @param html
*/
protected void tranformXml(File[] xmlfiles, File xsltFile) {
File html = null;
for (File xmlfile : xmlfiles) {
try {
File htmlroot = new File(getHtmlLocation(), getHTMLFileLocation(xmlfile));
if (!htmlroot.exists()) {
htmlroot.mkdirs();
}
html = new File(getNameFromXMLFilename(xmlfile));
applyXSLT(xsltFile, xmlfile, html);
} catch (Exception e) {
ApiPlugin.log(e);
}
}
}
/**
* Gets the HTML path to write out the transformed XML file to
*
* @param reportroot
* @param xmlfile
* @return
*/
protected String getHTMLFileLocation(File xmlfile) {
File reportRoot = new File(getXmlLocation());
IPath xml = new Path(xmlfile.getPath());
IPath report = new Path(reportRoot.getPath());
int segments = xml.matchingFirstSegments(report);
if (segments > 0) {
if (xml.getDevice() != null) {
xml = xml.setDevice(null);
}
IPath html = xml.removeFirstSegments(segments);
return html.removeLastSegments(1).toOSString();
}
return null;
}
/**
* Returns the name to use for the corresponding HTML file from the given
* XML file
*
* @param xmlFile
* @return the HTML name to use
*/
protected String getNameFromXMLFilename(File xmlFile) {
String fileName = xmlFile.getAbsolutePath();
int index = fileName.lastIndexOf('.');
StringBuilder buffer = new StringBuilder();
buffer.append(fileName.substring(getReportsRoot().getAbsolutePath().length(), index)).append(HTML_EXTENSION);
File htmlFile = new File(getHtmlLocation(), String.valueOf(buffer));
return htmlFile.getAbsolutePath();
}
/**
* Returns the collection of missing bundle names
*
* @param missingfile
* @return the collection of missing bundle names
* @throws Exception
*/
protected String[] getMissingBundles(File missingfile) throws Exception {
MissingHandler handler = new MissingHandler();
InputStream inputFile = null;
try{
inputFile = new FileInputStream(missingfile.getAbsolutePath());
getParser().parse(inputFile, handler);
}
catch (IOException ioe) {
ApiPlugin.log(ioe);
} finally {
if (inputFile != null) {
try {
inputFile.close();
} catch (IOException e) {
// ignore
}
}
}
return handler.missing.toArray(new String[handler.missing.size()]);
}
/**
* Returns the sentence describing the purpose / reason of the missing
* bundles
*
* @return a blurb describing the table of missing bundles
*/
protected String getMissingBundlesHeader() {
return SearchMessages.UseReportConverter_reported_missing_bundles;
}
/**
* Writes any existing metadata out to a meta.html file in the root of the
* HTML report location
*
* @param htmlroot
* @throws Exception
*/
void writeMetaPage(File htmlroot) throws Exception {
File meta = null;
PrintWriter writer = null;
try {
File file = new File(getReportsRoot(), "meta.xml"); //$NON-NLS-1$
if (!file.exists()) {
// do nothing if no meta.xml file
return;
}
String filename = "meta"; //$NON-NLS-1$
meta = new File(htmlroot, filename + HTML_EXTENSION);
if (!meta.exists()) {
meta.createNewFile();
}
StringBuilder buffer = new StringBuilder();
buffer.append(HTML_HEADER);
buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META);
buffer.append(OPEN_TITLE).append(SearchMessages.UseReportConverter_use_scan_info).append(CLOSE_TITLE);
buffer.append(CLOSE_HEAD);
buffer.append(OPEN_BODY);
buffer.append(OPEN_H3).append(SearchMessages.UseReportConverter_use_scan_info).append(CLOSE_H3);
writeMetadataSummary(buffer);
buffer.append(W3C_FOOTER);
// write file
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(meta), StandardCharsets.UTF_8));
writer.println(buffer.toString());
writer.flush();
} catch (IOException ioe) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, meta.getAbsolutePath()));
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* Writes out a summary of the missing required bundles
*
* @param htmlroot
* @return <code>true</code> if there was at least one missing bundle
*/
protected boolean writeMissingBundlesPage(final File htmlroot) throws Exception {
boolean hasMissing = false;
File missing = null;
PrintWriter writer = null;
try {
String filename = "missing"; //$NON-NLS-1$
missing = new File(htmlroot, filename + HTML_EXTENSION);
if (!missing.exists()) {
missing.createNewFile();
}
File file = new File(getReportsRoot(), "not_searched.xml"); //$NON-NLS-1$
if (!file.exists()) {
// try <root>/xml in case a raw reports root was specified
file = new File(getReportsRoot() + File.separator + "xml", "not_searched.xml"); //$NON-NLS-1$ //$NON-NLS-2$
}
TreeSet<String> sorted = new TreeSet<>(Util.componentsorter);
if (file.exists()) {
String[] missingBundles = getMissingBundles(file);
hasMissing = missingBundles.length > 0;
for (String missingBundle : missingBundles) {
sorted.add(missingBundle);
}
}
StringBuilder buffer = new StringBuilder();
buffer.append(HTML_HEADER);
buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META);
buffer.append(OPEN_TITLE).append(SearchMessages.UseReportConverter_missing_required).append(CLOSE_TITLE);
buffer.append(CLOSE_HEAD);
buffer.append(OPEN_BODY);
buffer.append(OPEN_H3).append(SearchMessages.UseReportConverter_missing_required).append(CLOSE_H3);
if (sorted.isEmpty()) {
buffer.append(SearchMessages.UseReportConverter_no_required_missing).append(BR);
} else {
buffer.append(OPEN_P).append(getMissingBundlesHeader()).append(CLOSE_P);
buffer.append("<table border=\"1\" width=\"50%\">\n"); //$NON-NLS-1$
buffer.append(OPEN_TR).append("<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" width=\"36%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_required_bundles).append(CLOSE_B).append(CLOSE_TD).append(CLOSE_TR); //$NON-NLS-1$ //$NON-NLS-2$
}
for (String value : sorted) {
buffer.append(OPEN_TR).append(OPEN_TD).append(value).append(CLOSE_TD).append(CLOSE_TR);
}
buffer.append(CLOSE_TABLE);
buffer.append(BR).append("<a href=\"not_searched.html\">").append(SearchMessages.UseReportConverter_back_to_not_searched).append(CLOSE_A); //$NON-NLS-1$
buffer.append(W3C_FOOTER);
// write file
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(missing), StandardCharsets.UTF_8));
writer.println(buffer.toString());
writer.flush();
} catch (IOException ioe) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, missing.getAbsolutePath()));
} finally {
if (writer != null) {
writer.close();
}
}
return hasMissing;
}
/**
* Writes out the file of components that were not searched: either because
* they appeared in an exclude list or they have no .api_description file
*
* @param htmlroot
*/
void writeNotSearchedPage(final File htmlroot) throws Exception {
File originhtml = null;
InputStream defaultXsltInputStream = null;
try {
String filename = "not_searched"; //$NON-NLS-1$
originhtml = new File(htmlroot, filename + HTML_EXTENSION);
if (!originhtml.exists()) {
originhtml.createNewFile();
}
File xml = new File(getReportsRoot(), filename + XML_EXTENSION);
if (!xml.exists()) {
// try <root>/xml in case a raw report root is specified
xml = new File(getReportsRoot() + File.separator + "xml", filename + XML_EXTENSION); //$NON-NLS-1$
}
defaultXsltInputStream = UseReportConverter.class.getResourceAsStream(getNotSearchedXSLPath());
Source xslt = null;
if (defaultXsltInputStream != null) {
xslt = new StreamSource(new BufferedInputStream(defaultXsltInputStream));
}
if (xslt == null) {
throw new Exception(SearchMessages.UseReportConverter_no_xstl_specified);
}
if (xml.exists()) {
try {
applyXSLT(xslt, xml, originhtml);
} catch (TransformerException e) {
useNotSearchedXml = true;
ApiPlugin.logErrorMessage(SearchMessages.UseReportConverter_te_applying_xslt_skipped);
}
}
} catch (IOException ioe) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, originhtml.getAbsolutePath()));
} catch (TransformerException te) {
throw new Exception(SearchMessages.UseReportConverter_te_applying_xslt_skipped, te);
} catch (CoreException e) {
throw new Exception(NLS.bind(SearchMessages.UseReportConverter_coreexception_writing_html_file, originhtml.getAbsolutePath()));
} finally {
if (defaultXsltInputStream != null) {
defaultXsltInputStream.close();
}
}
}
/**
* Returns path of XSL file to use when generating "not searched"
* information.
*
* @return path to the XSL file
*/
String getNotSearchedXSLPath() {
return "/notsearched.xsl"; //$NON-NLS-1$
}
/**
* Writes the referenced member index page
*
* @param report
* @param referees the listing of referencing bundles
*/
protected void writeReferencedMemberPage(final Report report, final List<Type> referees) throws Exception {
PrintWriter writer = null;
File originhtml = null;
try {
File htmlroot = new File(getHtmlLocation(), report.name);
if (!htmlroot.exists()) {
htmlroot.mkdirs();
}
originhtml = new File(htmlroot, "index.html"); //$NON-NLS-1$
if (!originhtml.exists()) {
originhtml.createNewFile();
}
StringBuilder buffer = new StringBuilder();
buffer.append(HTML_HEADER);
buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META);
buffer.append(REF_STYLE);
buffer.append(REF_SCRIPT);
buffer.append(OPEN_TITLE).append(getReferencedTypeTitle(report.name)).append(CLOSE_TITLE);
buffer.append(CLOSE_HEAD);
buffer.append(OPEN_BODY);
buffer.append(OPEN_H3).append(getReferencedTypeTitle(report.name)).append(CLOSE_H3);
buffer.append(OPEN_P).append(NLS.bind(SearchMessages.UseReportConverter_list_of_all_refing_bundles, new String[] {
"<a href=\"#bundles\">", "</a>" })).append(CLOSE_P); //$NON-NLS-1$ //$NON-NLS-2$
String additional = getAdditionalReferencedTypeInformation();
if (additional != null) {
buffer.append(additional);
}
buffer.append(getReferencesTableHeader(SearchMessages.UseReportConverter_references, SearchMessages.UseReportConverter_referenced_type, false));
CountGroup counts = null;
String link = null;
File typefile = null;
TreeMap<IMemberDescriptor, Member> map = null;
Type type = null;
for (Entry<Type, TreeMap<IMemberDescriptor, Member>> entry : report.children.entrySet()) {
map = entry.getValue();
type = entry.getKey();
counts = type.counts;
String fqname = Signatures.getQualifiedTypeSignature((IReferenceTypeDescriptor) type.desc);
typefile = new File(htmlroot, fqname + HTML_EXTENSION);
if (!typefile.exists()) {
typefile.createNewFile();
}
link = extractLinkFrom(htmlroot, typefile.getAbsolutePath());
buffer.append(getReferenceTableEntry(counts, link, fqname, false));
writeTypePage(map, type, typefile, fqname);
}
buffer.append(CLOSE_TABLE);
buffer.append(BR);
buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_referencing_bundles).append(CLOSE_H4);
buffer.append(OPEN_P).append(NLS.bind(SearchMessages.UseReportConverter_following_bundles_have_refs, report.name)).append(CLOSE_P);
buffer.append("<a name=\"bundles\">").append(CLOSE_A); //$NON-NLS-1$
buffer.append("<table border=\"1\" width=\"80%\">\n"); //$NON-NLS-1$
buffer.append(OPEN_TR);
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" width=\"50%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_bundle).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" width=\"20%\" align=\"center\">").append(OPEN_B).append(SearchMessages.UseReportConverter_version).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" width=\"10%\" align=\"center\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_count).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(CLOSE_TR);
Collections.sort(referees, compare);
IComponentDescriptor comp = null;
for (int i = 0; i < referees.size(); i++) {
type = referees.get(i);
comp = (IComponentDescriptor) type.desc;
buffer.append("<tr bgcolor=\"").append(getRowColour(counts)).append("\">\n"); //$NON-NLS-1$//$NON-NLS-2$
buffer.append("\t").append(OPEN_TD).append(OPEN_B).append(comp.getId()).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t").append(OPEN_TD).append(comp.getVersion()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t<td align=\"center\">").append(type.counts.getTotalRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
}
buffer.append(CLOSE_TABLE);
buffer.append(OPEN_P).append("<a href=\"../index.html\">").append(SearchMessages.UseReportConverter_back_to_bundle_index).append(CLOSE_A).append(CLOSE_P); //$NON-NLS-1$
buffer.append(W3C_FOOTER);
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(originhtml), StandardCharsets.UTF_8));
writer.println(buffer.toString());
writer.flush();
} catch (IOException ioe) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, originhtml.getAbsolutePath()));
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* Returns the colour to use based on certain counts
*
* @param counts
* @return the colour to use
* @since 1.1
*/
String getRowColour(CountGroup counts) {
if (counts.getTotalInternalRefCount() > 0) {
return INTERNAL_REFS_COLOUR;
}
if (counts.getTotalIllegalRefCount() > 0) {
return ILLEGAL_REFS_COLOUR;
}
return NORMAL_REFS_COLOUR;
}
/**
* Returns a string of additional information to print out at the top of the
* referenced types page.
*
* @return additional referenced type information.
*/
protected String getAdditionalReferencedTypeInformation() {
return null;
}
/**
* Returns the page title to use for the referenced types page
*
* @param bundle
* @return the page title for the referenced types page
*/
protected String getReferencedTypeTitle(String bundle) {
return NLS.bind(SearchMessages.UseReportConverter_types_used_in, bundle);
}
/**
* Writes the page that displays all of the members used in a type
*
* @param map
* @param type
* @param typefile
* @param typename
* @throws Exception
*/
void writeTypePage(Map<IMemberDescriptor, Member> map, Type type, File typefile, String typename) throws Exception {
PrintWriter writer = null;
try {
StringBuilder buffer = new StringBuilder();
buffer.append(HTML_HEADER);
buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META);
buffer.append(REF_STYLE);
buffer.append(REF_SCRIPT);
buffer.append(OPEN_TITLE).append(getTypeTitle(typename)).append(CLOSE_TITLE);
buffer.append(CLOSE_HEAD);
buffer.append(OPEN_BODY);
buffer.append(OPEN_H3).append(getTypeTitle(typename)).append(CLOSE_H3);
buffer.append(getTypeCountSummary(typename, type.counts, map.size()));
buffer.append(OPEN_H4).append(getTypeDetailsHeader()).append(CLOSE_H4);
buffer.append(OPEN_P).append(getTypeDetails()).append(CLOSE_P);
buffer.append("<div align=\"left\" class=\"main\">"); //$NON-NLS-1$
buffer.append("<table border=\"1\" width=\"80%\">\n"); //$NON-NLS-1$
buffer.append(OPEN_TR);
buffer.append("<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\">").append(OPEN_B).append(SearchMessages.UseReportConverter_member).append("</b></td>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buffer.append(CLOSE_TR);
IElementDescriptor desc = null;
for (Entry<IMemberDescriptor, Member> entry : map.entrySet()) {
desc = entry.getKey();
buffer.append(OPEN_TR);
buffer.append("<td align=\"left\">\n"); //$NON-NLS-1$
buffer.append(OPEN_B);
buffer.append("<a href=\"javascript:void(0)\" class=\"typeslnk\" onclick=\"expand(this)\" title=\""); //$NON-NLS-1$
buffer.append(getDisplayName(desc, true, true)).append("\">\n"); //$NON-NLS-1$
buffer.append("<span>[+] </span>").append(getDisplayName(desc, true, false)).append("\n"); //$NON-NLS-1$//$NON-NLS-2$
buffer.append(CLOSE_A).append(CLOSE_B);
buffer.append("<div colspan=\"6\" class=\"types\">\n"); //$NON-NLS-1$
buffer.append(getReferencesTable(entry.getValue())).append("\n"); //$NON-NLS-1$
buffer.append(CLOSE_DIV);
buffer.append(CLOSE_TR);
}
buffer.append(CLOSE_TABLE);
buffer.append(CLOSE_DIV);
buffer.append(OPEN_P).append("<a href=\"index.html\">").append(SearchMessages.UseReportConverter_back_to_bundle_index).append(CLOSE_A).append(CLOSE_P); //$NON-NLS-1$
buffer.append(W3C_FOOTER);
// write the file
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(typefile), StandardCharsets.UTF_8));
writer.print(buffer.toString());
writer.flush();
} catch (IOException ioe) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, typefile.getAbsolutePath()));
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* Returns the header to use for the section that describes the type details
* table
*
* @return the details header
*/
protected String getTypeDetailsHeader() {
return SearchMessages.UseReportConverter_reference_details;
}
/**
* Returns the blurb that follows the type details header
*
* @return the details information
* @see #getTypeDetailsHeader()
*/
protected String getTypeDetails() {
return SearchMessages.UseReportConverter_click_an_entry_to_see_details;
}
/**
* Returns the title to use for the type references page
*
* @param typename
* @return the type references page title
*/
protected String getTypeTitle(String typename) {
return NLS.bind(SearchMessages.UseReportConverter_usage_details, Signature.getSimpleName(typename));
}
/**
* Returns the nested table of references
*
* @return the nested table of references as a string
*/
String getReferencesTable(Member member) {
StringBuilder buffer = new StringBuilder();
buffer.append("<table width=\"100%\" border=\"0\" cellspacing=\"1\" cellpadding=\"6\">\n"); //$NON-NLS-1$
List<Reference> refs = null;
Reference ref = null;
for (Entry<String, List<Reference>> entry : member.children.entrySet()) {
buffer.append("<tr align=\"left\"> \n"); //$NON-NLS-1$
buffer.append("<td colspan=\"3\" bgcolor=\"#CCCCCC\">").append(OPEN_B).append(entry.getKey()).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
buffer.append("<tr bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append("<td align=\"left\" width=\"84%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_location).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("<td align=\"center\" width=\"8%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_line_number).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("<td align=\"center\" width=\"8%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_kind).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
refs = entry.getValue();
Collections.sort(refs, compare);
for (Iterator<Reference> iter2 = refs.iterator(); iter2.hasNext();) {
ref = iter2.next();
try {
String name = getDisplayName(ref.desc, false, true);
buffer.append(OPEN_TR);
buffer.append(OPEN_TD).append(name).append(CLOSE_TD);
buffer.append("<td align=\"center\">").append(ref.line).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("<td align=\"center\">").append("<span class=\"typeslnk\""); //$NON-NLS-1$//$NON-NLS-2$
if (ref.message != null) {
buffer.append(" title=\"").append(ref.message).append("\""); //$NON-NLS-1$ //$NON-NLS-2$
}
buffer.append(">").append(VisibilityModifiers.getVisibilityName(ref.vis)).append("</span>"); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(CLOSE_TD).append(CLOSE_TR);
} catch (CoreException ce) {
ApiPlugin.log(ce);
}
}
}
buffer.append(CLOSE_TABLE);
return buffer.toString();
}
/**
* Returns the name to display for the given {@link IElementDescriptor}
* which can be qualified or not
*
* @param desc
* @param qualifiedparams
* @param qualified
* @return the (un)-qualified name to display for the given
* {@link IElementDescriptor}
* @throws CoreException
*/
String getDisplayName(IElementDescriptor desc, boolean qualifiedparams, boolean qualified) throws CoreException {
String displayname = null;
switch (desc.getElementType()) {
case IElementDescriptor.TYPE: {
IReferenceTypeDescriptor rtype = (IReferenceTypeDescriptor) desc;
displayname = Signatures.getTypeSignature(rtype.getSignature(), rtype.getGenericSignature(), qualified);
break;
}
case IElementDescriptor.METHOD: {
IMethodDescriptor method = (IMethodDescriptor) desc;
if (qualified) {
displayname = Signatures.getQualifiedMethodSignature(method, qualifiedparams, qualifiedparams);
} else {
displayname = Signatures.getMethodSignature(method, qualifiedparams);
}
break;
}
case IElementDescriptor.FIELD: {
IFieldDescriptor field = (IFieldDescriptor) desc;
if (qualified) {
displayname = Signatures.getQualifiedFieldSignature(field);
} else {
displayname = field.getName();
}
break;
}
default:
break;
}
return displayname;
}
/**
* Extracts underlying link text from the given absolute filename based off
* the root file
*
* @param root
* @param fileName
* @return link text pruned via the given root file
*/
String extractLinkFrom(File root, String fileName) {
StringBuilder buffer = new StringBuilder();
String substring = fileName.substring(root.getAbsolutePath().length()).replace('\\', '/');
buffer.append('.');
if (substring.charAt(0) != '/') {
buffer.append('/');
}
buffer.append(substring);
return String.valueOf(buffer);
}
/**
* Returns the page title for the index page
*
* @return the index page title
*/
protected String getIndexTitle() {
return SearchMessages.UseReportConverter_bundle_usage_information;
}
/**
* Writes the main index file for the reports
*
* @param scanResult a list of {@link Report} objects returns from the use
* scan parser
* @param reportsRoot
*/
protected void writeIndexPage(List<?> scanResult) throws Exception {
Collections.sort(scanResult, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return ((Report) o1).name.compareTo(((Report) o2).name);
}
});
PrintWriter writer = null;
try {
File reportIndex = new File(getHtmlLocation(), "index.html"); //$NON-NLS-1$
if (!reportIndex.exists()) {
reportIndex.createNewFile();
}
setReportIndex(reportIndex);
StringBuilder buffer = new StringBuilder();
buffer.append(HTML_HEADER);
buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META);
writeMetadataHeaders(buffer);
buffer.append(OPEN_TITLE).append(getIndexTitle()).append(CLOSE_TITLE);
buffer.append(CLOSE_HEAD);
buffer.append(OPEN_BODY);
buffer.append(OPEN_H3).append(getIndexTitle()).append(CLOSE_H3);
try {
getMetadata();
writeMetadataSummary(buffer);
getFilteredCount();
writeFilterCount(buffer);
} catch (Exception e) {
// do nothing, failed meta-data should not prevent the index
// from being written
}
buffer.append(OPEN_H4).append(SearchMessages.UseReportConvertor_additional_infos_section).append(CLOSE_H4);
if (hasMissing()) {
buffer.append(OPEN_P);
buffer.append(NLS.bind(SearchMessages.UseReportConverter_missing_bundles_prevented_scan, new String[] {
" <a href=\"./missing.html\">", "</a>" })); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(CLOSE_P);
}
buffer.append(OPEN_P);
buffer.append(NLS.bind(SearchMessages.UseReportConverter_bundles_that_were_not_searched, new String[] {
useNotSearchedXml == false ? "<a href=\"./not_searched.html\">" : "<a href=\"../xml/not_searched.xml\">", //$NON-NLS-1$//$NON-NLS-2$
"</a></p>\n" }));//$NON-NLS-1$
String additional = getAdditionalIndexInfo(scanResult.size() > 0);
if (additional != null) {
buffer.append(additional);
}
if (scanResult.size() > 0) {
buffer.append(OPEN_P).append(SearchMessages.UseReportConverter_inlined_description).append(CLOSE_P);
buffer.append(getColourLegend());
buffer.append(getReferencesTableHeader(SearchMessages.UseReportConverter_references, SearchMessages.UseReportConverter_bundle, true));
if (scanResult.size() > 0) {
File refereehtml = null;
String link = null;
for (Object obj : scanResult) {
if (obj instanceof Report) {
Report report = (Report) obj;
refereehtml = new File(getReportsRoot(), report.name + File.separator + "index.html"); //$NON-NLS-1$
link = extractLinkFrom(getReportsRoot(), refereehtml.getAbsolutePath());
buffer.append(getReferenceTableEntry(report.counts, link, report.name, true));
}
}
buffer.append(CLOSE_TABLE);
}
} else {
buffer.append(getNoReportsInformation());
}
buffer.append(W3C_FOOTER);
buffer.append(CLOSE_BODY).append(CLOSE_HTML);
// write the file
writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(reportIndex), StandardCharsets.UTF_8));
writer.print(buffer.toString());
writer.flush();
} catch (IOException e) {
throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, getReportIndex().getAbsolutePath()));
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* Returns a table describing what all of the colours mean in the reports
*
* @return a colour legend table
* @since 1.1
*/
protected String getColourLegend() {
StringBuilder buffer = new StringBuilder();
buffer.append(OPEN_P);
buffer.append("<table width=\"20%\" border=\"1\">"); //$NON-NLS-1$
buffer.append(OPEN_TR);
buffer.append("<td width=\"25px\" bgcolor=\"").append(INTERNAL_REFS_COLOUR).append("\">\n").append("&nbsp;").append(CLOSE_TD); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
buffer.append("<td width=\"82%\">").append(SearchMessages.UseReportConverter_marks_internal_references).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append("<td width=\"25px\" bgcolor=\"").append(ILLEGAL_REFS_COLOUR).append("\">\n").append("&nbsp;").append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buffer.append("<td width=\"82%\">").append(SearchMessages.UseReportConverter_marks_illegal_use_references).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
buffer.append(CLOSE_TABLE);
buffer.append(CLOSE_P);
return buffer.toString();
}
/**
* @return the string to write if there are no reported bundles
*/
protected String getNoReportsInformation() {
StringBuilder buffer = new StringBuilder();
buffer.append(OPEN_P).append(BR).append(SearchMessages.UseReportConverter_no_reported_usage).append(CLOSE_P);
return buffer.toString();
}
/**
* This method is called during the HTML header creation phase to allow META
* header elements to be written for metadata objects
*
* @param buffer
* @throws Exception
*/
void writeMetadataHeaders(StringBuilder buffer) throws Exception {
writeMetaTag(buffer, "description", SearchMessages.UseReportConverter_root_index_description); //$NON-NLS-1$
// TODO could write metadata information here
}
/**
* This method is called during the initial index page creation to allow and
* executive summary of the use scan to be written out from metadata
*
* @param buffer
* @throws Exception
*/
void writeMetadataSummary(StringBuilder buffer) throws Exception {
buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_scan_details).append(CLOSE_H4);
if (this.metadata != null) {
buffer.append("<table border=\"0px\" title=\"").append(SearchMessages.UseReportConverter_scan_details).append("\"width=\"50%\">"); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_scan_date).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.getRunAtDate()).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_description).append(CLOSE_TD);
String desc = this.metadata.getDescription();
buffer.append(openTD(36)).append((desc != null ? desc : SearchMessages.UseReportConverter_none)).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_includes_API_refs).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.includesAPI() ? SearchMessages.UseReportConverter_includes_true : SearchMessages.UseReportConverter_includes_false).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_includes_internal_refs).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.includesInternal() ? SearchMessages.UseReportConverter_includes_true : SearchMessages.UseReportConverter_includes_false).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_includes_illegal_use).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.includesIllegalUse() ? SearchMessages.UseReportConverter_includes_true : SearchMessages.UseReportConverter_includes_false).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_baseline_loc).append(CLOSE_TD);
buffer.append(openTD(36)).append(TextProcessor.process(this.metadata.getBaselineLocation())).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_scope_pattern).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.getScopePattern()).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_reference_pattern).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.metadata.getReferencePattern()).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_report_location).append(CLOSE_TD);
buffer.append(openTD(36)).append(TextProcessor.process(this.metadata.getReportLocation())).append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_api_pattern).append(CLOSE_TD);
buffer.append(openTD(36));
String[] patterns = this.metadata.getApiPatterns();
if (patterns != null) {
for (String pattern : patterns) {
buffer.append(pattern).append(BR);
}
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_internal_patterns).append(CLOSE_TD);
buffer.append(openTD(36));
patterns = this.metadata.getInternalPatterns();
if (patterns != null) {
for (String pattern : patterns) {
buffer.append(pattern).append(BR);
}
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_archive_patterns).append(CLOSE_TD);
buffer.append(openTD(36));
patterns = this.metadata.getArchivePatterns();
if (patterns != null) {
for (String pattern : patterns) {
buffer.append(pattern).append(BR);
}
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_filter_pattern).append(CLOSE_TD);
buffer.append(openTD(36));
if (this.frompatterns != null) {
for (Pattern frompattern : this.frompatterns) {
buffer.append(frompattern.pattern()).append(BR);
}
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_to_filter_patterns).append(CLOSE_TD);
buffer.append(openTD(36));
if (this.topatterns != null) {
for (Pattern topattern : this.topatterns) {
buffer.append(topattern.pattern()).append(BR);
}
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_additional_filters).append(CLOSE_TD);
buffer.append(openTD(36));
if (this.metadata.getAdditionalfilters() != null && !this.metadata.getAdditionalfilters().isEmpty()) {
buffer.append(TextProcessor.process(this.metadata.getAdditionalfilters()));
} else {
buffer.append(SearchMessages.UseReportConverter_none);
}
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(CLOSE_TD);
buffer.append(CLOSE_TR);
buffer.append(CLOSE_TABLE);
} else {
buffer.append(OPEN_P).append(SearchMessages.UseReportConverter_no_additional_scan_info).append(CLOSE_P);
}
}
void writeFilterCount(StringBuilder buffer) throws Exception {
boolean isAdditionFilterProvided = this.metadata.getAdditionalfilters() != null && !this.metadata.getAdditionalfilters().isEmpty();
if (this.filteredCount != -1 && isAdditionFilterProvided) {
buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_filter_information).append(CLOSE_H4);
buffer.append(OPEN_TR);
buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_number_filtered).append(CLOSE_TD);
buffer.append(openTD(36)).append(this.filteredCount).append(CLOSE_TD);
buffer.append(CLOSE_TR);
}
}
/**
* Returns the use metadata from this scan
*
* @return
* @throws Exception
*/
IMetadata getMetadata() throws Exception {
if (this.metadata == null) {
File xml = null;
try {
xml = new File(getReportsRoot(), "meta" + XML_EXTENSION); //$NON-NLS-1$
if (!xml.exists()) {
// try looking in the default 'xml' directory as a raw
// report root
// might have been specified
xml = new File(getReportsRoot() + File.separator + "xml", "meta" + XML_EXTENSION); //$NON-NLS-1$//$NON-NLS-2$
}
if (xml.exists()) {
String xmlstr = Util.getFileContentAsString(xml);
Element doc = Util.parseDocument(xmlstr.trim());
this.metadata = new UseMetadata();
Element element = null;
String value = null, name = null;
NodeList nodes = doc.getElementsByTagName("*"); //$NON-NLS-1$
for (int i = 0; i < nodes.getLength(); i++) {
element = (Element) nodes.item(i);
value = element.getAttribute(UseMetadata.VALUE);
name = element.getNodeName();
if (UseMetadata.FLAGS.equals(name)) {
try {
this.metadata.setSearchflags(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
// do nothing
}
continue;
}
if (UseMetadata.RUNATDATE.equals(name)) {
this.metadata.setRunAtDate(value);
continue;
}
if (UseMetadata.DESCRIPTION.equals(name)) {
this.metadata.setDescription(value);
continue;
}
if (UseMetadata.BASELINELOCATION.equals(name)) {
this.metadata.setBaselineLocation(value);
continue;
}
if (UseMetadata.REPORTLOCATION.equals(name)) {
this.metadata.setReportLocation(value);
continue;
}
if (UseMetadata.SCOPEPATTERN.equals(name)) {
this.metadata.setScopePattern(value);
continue;
}
if (UseMetadata.REFERENCEPATTERN.equals(name)) {
this.metadata.setReferencePattern(value);
continue;
}
if (UseMetadata.APIPATTERNS.equals(name)) {
this.metadata.setApiPatterns(readPatterns(element));
continue;
}
if (UseMetadata.INTERNALPATTERNS.equals(name)) {
this.metadata.setInternalPatterns(readPatterns(element));
continue;
}
if (UseMetadata.ARCHIVEPATTERNS.equals(name)) {
this.metadata.setArchivePatterns(readPatterns(element));
continue;
}
if (UseMetadata.ADDITIONALFILTERS.equals(name)) {
this.metadata.setAdditionalfilters(value);
continue;
}
}
}
} catch (CoreException e) {
throw new Exception(NLS.bind(SearchMessages.UseReportConverter_core_exep_reading_metadata, xml.getAbsolutePath()));
}
}
return this.metadata;
}
/**
* Returns the use filtered count from this scan
*
* @return
* @throws Exception
*/
int getFilteredCount() throws Exception {
if (this.filteredCount == -1) {
File xml = null;
try {
xml = new File(getReportsRoot(), "counts" + XML_EXTENSION); //$NON-NLS-1$
if (!xml.exists()) {
// try looking in the default 'xml' directory as a raw
// report root
// might have been specified
xml = new File(getReportsRoot() + File.separator + "xml", "meta" + XML_EXTENSION); //$NON-NLS-1$//$NON-NLS-2$
}
if (xml.exists()) {
String xmlstr = Util.getFileContentAsString(xml);
Element doc = Util.parseDocument(xmlstr.trim());
NamedNodeMap nodes = doc.getAttributes();
for (int i = 0; i < nodes.getLength(); i++) {
Node element = nodes.item(i);
String value = element.getNodeValue();
String name = element.getNodeName();
if (name.equals(IApiXmlConstants.ATTR_COUNT_FILTERED)) {
filteredCount = Integer.parseInt(value);
}
}
}
} catch (CoreException e) {
throw new Exception(NLS.bind(SearchMessages.UseReportConverter_core_exep_reading_metadata, xml.getAbsolutePath()));
}
}
return filteredCount;
}
/**
* Reads saved patterns from the meta.xml file
*
* @param element
* @return the array of patterns or <code>null</code>
*/
private String[] readPatterns(Element element) {
String[] pats = null;
NodeList patterns = element.getElementsByTagName(UseMetadata.PATTERN);
int length = patterns.getLength();
if (length > 0) {
pats = new String[length];
for (int j = 0; j < length; j++) {
pats[j] = ((Element) patterns.item(j)).getAttribute(UseMetadata.VALUE);
}
}
return pats;
}
/**
* Writes out a META tag of the kind <code>description</code>
*
* @param buffer
* @param description
*/
void writeMetaTag(StringBuilder buffer, String name, String content) {
buffer.append("<meta name=\"").append(name).append("\" content=\"").append(content).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/**
* Returns the HTML markup for the default references table header. Where
* the first column contains the linked item and the following five columns
* are API, Internal, Permissible, Fragment-Permissible and Other reference
* counts respectively
*
* @param columnname
* @param includeversion
* @return the default references table header
*/
String getReferencesTableHeader(String sectionname, String columnname, boolean includeversion) {
StringBuilder buffer = new StringBuilder();
buffer.append(OPEN_H4).append(sectionname).append(CLOSE_H4);
buffer.append("<table border=\"1\" width=\"80%\">\n"); //$NON-NLS-1$
buffer.append(OPEN_TR);
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" width=\"30%\">").append(OPEN_B).append(columnname).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$
if (includeversion) {
// version header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"20%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_version_column_description).append("\"\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_version).append(CLOSE_B).append(CLOSE_TD);
}
// API header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_api_ref_description).append("\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_api_references).append(CLOSE_B).append(CLOSE_TD);
// Internal header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_internal_ref_description).append("\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_internal_references).append(CLOSE_B).append(CLOSE_TD);
// Permissible header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_permissible_ref_description).append("\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_internal_permissible_references).append(CLOSE_B).append(CLOSE_TD);
// fragment permissible header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_fragment_ref_description).append("\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_fragment_permissible_references).append(CLOSE_B).append(CLOSE_TD);
// illegal use header
buffer.append("\t<td bgcolor=\"").append(REFERENCES_TABLE_HEADER_COLOUR).append("\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ //$NON-NLS-2$
buffer.append(SearchMessages.UseReportConverter_illegal_ref_description).append("\">"); //$NON-NLS-1$
buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_illegal).append(CLOSE_B).append(CLOSE_TD);
return buffer.toString();
}
/**
* Returns the HTML markup for one entry in the default references table.
* Where the first column contains the linked item and the following five
* columns are Version, API, Internal, Permissible, Fragment-Permissible
* reference counts respectively
*
* @param counts
* @param link
* @param linktext
* @param includeversion
* @return a single reference table entry
*/
String getReferenceTableEntry(CountGroup counts, String link, String linktext, boolean includeversion) {
StringBuilder buffer = new StringBuilder();
buffer.append("<tr bgcolor=\"").append(getRowColour(counts)).append("\">\n"); //$NON-NLS-1$//$NON-NLS-2$
buffer.append("\t<td><b><a href=\"").append(link).append("\">").append(getBundleOnlyName(linktext)).append("</a>").append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (includeversion) {
buffer.append("\t<td align=\"left\">").append(getVersion(linktext)).append(CLOSE_TD); //$NON-NLS-1$
}
buffer.append("\t<td align=\"center\">").append(counts.getTotalApiRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t<td align=\"center\">").append(counts.getTotalInternalRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t<td align=\"center\">").append(counts.getTotalPermissableRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t<td align=\"center\">").append(counts.getTotalFragmentPermissibleRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append("\t<td align=\"center\">").append(counts.getTotalIllegalRefCount()).append(CLOSE_TD); //$NON-NLS-1$
buffer.append(CLOSE_TR);
return buffer.toString();
}
String getBundleOnlyName(String text) {
int idx = text.indexOf('(');
if (idx > -1) {
return text.substring(0, idx - 1);
}
return text;
}
/**
* Returns the version string from the text (if any)
*
* @param text
* @return
* @since 1.1
*/
String getVersion(String text) {
int idx = text.indexOf('(');
if (idx > -1) {
int idx2 = text.indexOf(')', idx);
String version = text.substring(idx + 1, idx2);
try {
Version ver = new Version(version);
return ver.toString();
} catch (IllegalArgumentException iae) {
// do nothing, not a valid version
}
}
return "-"; //$NON-NLS-1$
}
/**
* Allows additional infos to be added to the HTML at the top of the report
* page
*
* @param hasreports
*
* @return additional information string to add
*/
protected String getAdditionalIndexInfo(boolean hasreports) {
return null;
}
/**
* Returns HTML summary for references from a specific component.
*
* @param typename
* @param counts
* @return HTML as a string
*/
protected String getTypeCountSummary(String typename, CountGroup counts, int membercount) {
StringBuilder buffer = new StringBuilder();
buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_summary).append(CLOSE_H4);
buffer.append(OPEN_P).append(NLS.bind(SearchMessages.UseReportConverter___has_total_refs, new String[] {
typename, Integer.toString(counts.getTotalRefCount()),
Integer.toString(membercount) })).append(CLOSE_P);
return buffer.toString();
}
}