| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2009 IBM Corporation and others. |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * IBM Corporation - initial API and implementation |
| 10 | *******************************************************************************/ |
| 11 | package org.eclipse.pde.api.tools.internal.search; |
| 12 | |
| 13 | import java.io.BufferedInputStream; |
| 14 | import java.io.BufferedWriter; |
| 15 | import java.io.File; |
| 16 | import java.io.FileWriter; |
| 17 | import java.io.IOException; |
| 18 | import java.io.InputStream; |
| 19 | import java.io.PrintWriter; |
| 20 | import java.util.ArrayList; |
| 21 | import java.util.Collections; |
| 22 | import java.util.Comparator; |
| 23 | import java.util.HashMap; |
| 24 | import java.util.Iterator; |
| 25 | import java.util.List; |
| 26 | import java.util.StringTokenizer; |
| 27 | import java.util.TreeMap; |
| 28 | import java.util.TreeSet; |
| 29 | import java.util.Map.Entry; |
| 30 | import java.util.regex.Pattern; |
| 31 | import java.util.regex.PatternSyntaxException; |
| 32 | |
| 33 | import javax.xml.parsers.ParserConfigurationException; |
| 34 | import javax.xml.parsers.SAXParser; |
| 35 | import javax.xml.parsers.SAXParserFactory; |
| 36 | import javax.xml.transform.Result; |
| 37 | import javax.xml.transform.Source; |
| 38 | import javax.xml.transform.Transformer; |
| 39 | import javax.xml.transform.TransformerException; |
| 40 | import javax.xml.transform.TransformerFactory; |
| 41 | import javax.xml.transform.stream.StreamResult; |
| 42 | import javax.xml.transform.stream.StreamSource; |
| 43 | |
| 44 | import org.eclipse.core.runtime.CoreException; |
| 45 | import org.eclipse.core.runtime.IPath; |
| 46 | import org.eclipse.core.runtime.IProgressMonitor; |
| 47 | import org.eclipse.core.runtime.Path; |
| 48 | import org.eclipse.core.runtime.SubMonitor; |
| 49 | import org.eclipse.jdt.core.Signature; |
| 50 | import org.eclipse.osgi.util.NLS; |
| 51 | import org.eclipse.pde.api.tools.internal.IApiXmlConstants; |
| 52 | import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
| 53 | import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers; |
| 54 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor; |
| 55 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor; |
| 56 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IFieldDescriptor; |
| 57 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor; |
| 58 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMethodDescriptor; |
| 59 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor; |
| 60 | import org.eclipse.pde.api.tools.internal.util.Signatures; |
| 61 | import org.eclipse.pde.api.tools.internal.util.Util; |
| 62 | import org.w3c.dom.Element; |
| 63 | import org.w3c.dom.NodeList; |
| 64 | import org.xml.sax.Attributes; |
| 65 | import org.xml.sax.SAXException; |
| 66 | import org.xml.sax.helpers.DefaultHandler; |
| 67 | |
| 68 | /** |
| 69 | * This class converts a collection of API use report XML files |
| 70 | * from a given location to a corresponding collection of |
| 71 | * HTML in a given location |
| 72 | * |
| 73 | * @since 1.0.1 |
| 74 | */ |
| 75 | public class UseReportConverter extends HTMLConvertor { |
| 76 | |
| 77 | /** |
| 78 | * Use visitor to write the reports |
| 79 | */ |
| 80 | class Visitor extends UseScanVisitor { |
| 81 | |
| 82 | ArrayList reports = new ArrayList(); |
| 83 | Report currentreport = null; |
| 84 | Type currenttype = null, currentreferee = null; |
| 85 | Member currentmember = null; |
| 86 | HashMap keys = new HashMap(); |
| 87 | ArrayList referees = new ArrayList(); |
| 88 | |
| 89 | /** |
| 90 | * Returns if the reference should be reported or not |
| 91 | * @param desc |
| 92 | * @return true if the reference should be reported false otherwise |
| 93 | */ |
| 94 | private boolean acceptReference(IMemberDescriptor desc) { |
| 95 | if(filterPatterns != null) { |
| 96 | for (int i = 0; i < filterPatterns.length; i++) { |
| 97 | if(filterPatterns[i].matcher(desc.getPackage().getName()).find()) { |
| 98 | //TODO should we record filtered results? |
| 99 | return false; |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | return true; |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Returns the enclosing {@link IReferenceTypeDescriptor} for the given member |
| 108 | * descriptor |
| 109 | * @param member |
| 110 | * @return the enclosing {@link IReferenceTypeDescriptor} or <code>null</code> |
| 111 | */ |
| 112 | IReferenceTypeDescriptor getEnclosingDescriptor(IMemberDescriptor member) { |
| 113 | switch(member.getElementType()) { |
| 114 | case IElementDescriptor.TYPE: { |
| 115 | return (IReferenceTypeDescriptor) member; |
| 116 | } |
| 117 | case IElementDescriptor.METHOD: |
| 118 | case IElementDescriptor.FIELD: { |
| 119 | return member.getEnclosingType(); |
| 120 | } |
| 121 | } |
| 122 | return null; |
| 123 | } |
| 124 | |
| 125 | /* (non-Javadoc) |
| 126 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#visitComponent(org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor) |
| 127 | */ |
| 128 | public boolean visitComponent(IComponentDescriptor target) { |
| 129 | this.currentreport = new Report(); |
| 130 | this.currentreport.name = composeName(target.getId(), target.getVersion()); |
| 131 | this.reports.add(this.currentreport); |
| 132 | return true; |
| 133 | } |
| 134 | |
| 135 | /* (non-Javadoc) |
| 136 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#endVisit(org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor) |
| 137 | */ |
| 138 | public void endVisit(IComponentDescriptor target) { |
| 139 | try { |
| 140 | long start = 0; |
| 141 | if(DEBUG) { |
| 142 | System.out.println("Writing report for bundle: "+target.getId()); //$NON-NLS-1$ |
| 143 | start = System.currentTimeMillis(); |
| 144 | } |
| 145 | if(this.currentreport.counts.getTotalRefCount() > 0) { |
| 146 | writeReferencedMemberPage(this.currentreport, this.referees); |
| 147 | } |
| 148 | else { |
| 149 | this.reports.remove(this.currentreport); |
| 150 | } |
| 151 | if(DEBUG) { |
| 152 | System.out.println("done in: "+(System.currentTimeMillis()-start)+ " ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 153 | } |
| 154 | } |
| 155 | catch(Exception e) { |
| 156 | ApiPlugin.log(e); |
| 157 | } |
| 158 | finally { |
| 159 | //clear any children as we have written them out - keep the report object to write a sorted index page |
| 160 | this.currentreport.children.clear(); |
| 161 | this.keys.clear(); |
| 162 | this.referees.clear(); |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | /* (non-Javadoc) |
| 167 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#visitReferencingComponent(org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor) |
| 168 | */ |
| 169 | public boolean visitReferencingComponent(IComponentDescriptor component) { |
| 170 | this.currentreferee = new Type(component); |
| 171 | return true; |
| 172 | } |
| 173 | /* (non-Javadoc) |
| 174 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#endVisitReferencingComponent(org.eclipse.pde.api.tools.internal.provisional.descriptors.IComponentDescriptor) |
| 175 | */ |
| 176 | public void endVisitReferencingComponent(IComponentDescriptor component) { |
| 177 | if(this.currentreferee.counts.getTotalRefCount() > 0) { |
| 178 | this.referees.add(this.currentreferee); |
| 179 | } |
| 180 | } |
| 181 | /* (non-Javadoc) |
| 182 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#visitMember(org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor) |
| 183 | */ |
| 184 | public boolean visitMember(IMemberDescriptor referencedMember) { |
| 185 | IReferenceTypeDescriptor desc = getEnclosingDescriptor(referencedMember); |
| 186 | if(desc == null) { |
| 187 | return false; |
| 188 | } |
| 189 | this.currenttype = (Type) this.keys.get(desc); |
| 190 | if(this.currenttype == null) { |
| 191 | this.currenttype = new Type(desc); |
| 192 | this.keys.put(desc, this.currenttype); |
| 193 | } |
| 194 | TreeMap map = (TreeMap) this.currentreport.children.get(this.currenttype); |
| 195 | if(map == null) { |
| 196 | map = new TreeMap(compare); |
| 197 | this.currentreport.children.put(this.currenttype, map); |
| 198 | } |
| 199 | this.currentmember = (Member) map.get(referencedMember); |
| 200 | if(this.currentmember == null) { |
| 201 | this.currentmember = new Member(referencedMember); |
| 202 | map.put(referencedMember, this.currentmember); |
| 203 | } |
| 204 | return true; |
| 205 | } |
| 206 | |
| 207 | /* (non-Javadoc) |
| 208 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#endVisitMember(org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor) |
| 209 | */ |
| 210 | public void endVisitMember(IMemberDescriptor referencedMember) { |
| 211 | if(this.currentmember.children.size() == 0) { |
| 212 | TreeMap map = (TreeMap) this.currentreport.children.get(this.currenttype); |
| 213 | map.remove(referencedMember); |
| 214 | } |
| 215 | if(this.currenttype.counts.getTotalRefCount() == 0) { |
| 216 | IReferenceTypeDescriptor desc = getEnclosingDescriptor(referencedMember); |
| 217 | if(desc != null) { |
| 218 | this.keys.remove(desc); |
| 219 | this.currentreport.children.remove(this.currenttype); |
| 220 | } |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | /* (non-Javadoc) |
| 225 | * @see org.eclipse.pde.api.tools.internal.search.UseScanVisitor#visitReference(int, org.eclipse.pde.api.tools.internal.provisional.descriptors.IMemberDescriptor, int, int) |
| 226 | */ |
| 227 | public void visitReference(int refKind, IMemberDescriptor fromMember, int lineNumber, int visibility) { |
| 228 | if(!acceptReference(fromMember)) { |
| 229 | return; |
| 230 | } |
| 231 | String refname = org.eclipse.pde.api.tools.internal.builder.Reference.getReferenceText(refKind); |
| 232 | ArrayList refs = (ArrayList) this.currentmember.children.get(refname); |
| 233 | if(refs == null) { |
| 234 | refs = new ArrayList(); |
| 235 | this.currentmember.children.put(refname, refs); |
| 236 | } |
| 237 | refs.add(new Reference(fromMember, lineNumber, visibility)); |
| 238 | switch(fromMember.getElementType()) { |
| 239 | case IElementDescriptor.TYPE: { |
| 240 | switch(visibility) { |
| 241 | case VisibilityModifiers.API: { |
| 242 | this.currentmember.counts.total_api_type_count++; |
| 243 | this.currenttype.counts.total_api_type_count++; |
| 244 | this.currentreferee.counts.total_api_type_count++; |
| 245 | this.currentreport.counts.total_api_type_count++; |
| 246 | break; |
| 247 | } |
| 248 | case VisibilityModifiers.PRIVATE: { |
| 249 | this.currentmember.counts.total_private_type_count++; |
| 250 | this.currenttype.counts.total_private_type_count++; |
| 251 | this.currentreferee.counts.total_private_type_count++; |
| 252 | this.currentreport.counts.total_private_type_count++; |
| 253 | break; |
| 254 | } |
| 255 | case VisibilityModifiers.PRIVATE_PERMISSIBLE: { |
| 256 | this.currentmember.counts.total_permissable_type_count++; |
| 257 | this.currenttype.counts.total_permissable_type_count++; |
| 258 | this.currentreferee.counts.total_permissable_type_count++; |
| 259 | this.currentreport.counts.total_permissable_type_count++; |
| 260 | break; |
| 261 | } |
| 262 | case FRAGMENT_PERMISSIBLE: { |
| 263 | this.currentmember.counts.total_fragment_permissible_type_count++; |
| 264 | this.currenttype.counts.total_fragment_permissible_type_count++; |
| 265 | this.currentreferee.counts.total_fragment_permissible_type_count++; |
| 266 | this.currentreport.counts.total_fragment_permissible_type_count++; |
| 267 | break; |
| 268 | } |
| 269 | default: { |
| 270 | this.currentmember.counts.total_other_type_count++; |
| 271 | this.currenttype.counts.total_other_type_count++; |
| 272 | this.currentreferee.counts.total_other_type_count++; |
| 273 | this.currentreport.counts.total_other_type_count++; |
| 274 | break; |
| 275 | } |
| 276 | } |
| 277 | break; |
| 278 | } |
| 279 | case IElementDescriptor.METHOD: { |
| 280 | switch(visibility) { |
| 281 | case VisibilityModifiers.API: { |
| 282 | this.currentmember.counts.total_api_method_count++; |
| 283 | this.currenttype.counts.total_api_method_count++; |
| 284 | this.currentreferee.counts.total_api_method_count++; |
| 285 | this.currentreport.counts.total_api_method_count++; |
| 286 | break; |
| 287 | } |
| 288 | case VisibilityModifiers.PRIVATE: { |
| 289 | this.currentmember.counts.total_private_method_count++; |
| 290 | this.currenttype.counts.total_private_method_count++; |
| 291 | this.currentreferee.counts.total_private_method_count++; |
| 292 | this.currentreport.counts.total_private_method_count++; |
| 293 | break; |
| 294 | } |
| 295 | case VisibilityModifiers.PRIVATE_PERMISSIBLE: { |
| 296 | this.currentmember.counts.total_permissable_method_count++; |
| 297 | this.currenttype.counts.total_permissable_method_count++; |
| 298 | this.currentreferee.counts.total_permissable_method_count++; |
| 299 | this.currentreport.counts.total_permissable_method_count++; |
| 300 | break; |
| 301 | } |
| 302 | case FRAGMENT_PERMISSIBLE: { |
| 303 | this.currentmember.counts.total_fragment_permissible_method_count++; |
| 304 | this.currenttype.counts.total_fragment_permissible_method_count++; |
| 305 | this.currentreferee.counts.total_fragment_permissible_method_count++; |
| 306 | this.currentreport.counts.total_fragment_permissible_method_count++; |
| 307 | break; |
| 308 | } |
| 309 | default: { |
| 310 | this.currentmember.counts.total_other_method_count++; |
| 311 | this.currenttype.counts.total_other_method_count++; |
| 312 | this.currentreferee.counts.total_other_method_count++; |
| 313 | this.currentreport.counts.total_other_method_count++; |
| 314 | break; |
| 315 | } |
| 316 | } |
| 317 | break; |
| 318 | } |
| 319 | case IElementDescriptor.FIELD: { |
| 320 | switch(visibility) { |
| 321 | case VisibilityModifiers.API: { |
| 322 | this.currentmember.counts.total_api_field_count++; |
| 323 | this.currenttype.counts.total_api_field_count++; |
| 324 | this.currentreferee.counts.total_api_field_count++; |
| 325 | this.currentreport.counts.total_api_field_count++; |
| 326 | break; |
| 327 | } |
| 328 | case VisibilityModifiers.PRIVATE: { |
| 329 | this.currentmember.counts.total_private_field_count++; |
| 330 | this.currenttype.counts.total_private_field_count++; |
| 331 | this.currentreferee.counts.total_private_field_count++; |
| 332 | this.currentreport.counts.total_private_field_count++; |
| 333 | break; |
| 334 | } |
| 335 | case VisibilityModifiers.PRIVATE_PERMISSIBLE: { |
| 336 | this.currentmember.counts.total_permissable_field_count++; |
| 337 | this.currenttype.counts.total_permissable_field_count++; |
| 338 | this.currentreferee.counts.total_permissable_field_count++; |
| 339 | this.currentreport.counts.total_permissable_field_count++; |
| 340 | break; |
| 341 | } |
| 342 | case FRAGMENT_PERMISSIBLE: { |
| 343 | this.currentmember.counts.total_fragment_permissible_field_count++; |
| 344 | this.currenttype.counts.total_fragment_permissible_field_count++; |
| 345 | this.currentreferee.counts.total_fragment_permissible_field_count++; |
| 346 | this.currentreport.counts.total_fragment_permissible_field_count++; |
| 347 | break; |
| 348 | } |
| 349 | default: { |
| 350 | this.currentmember.counts.total_other_field_count++; |
| 351 | this.currenttype.counts.total_other_field_count++; |
| 352 | this.currentreferee.counts.total_other_field_count++; |
| 353 | this.currentreport.counts.total_other_field_count++; |
| 354 | break; |
| 355 | } |
| 356 | } |
| 357 | break; |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | /** |
| 364 | * Comparator for use report items |
| 365 | */ |
| 366 | static Comparator compare = new Comparator() { |
| 367 | public int compare(Object o1, Object o2) { |
| 368 | if(o1 instanceof String && o2 instanceof String) { |
| 369 | return ((String)o1).compareTo((String)o2); |
| 370 | } |
| 371 | if(o1 instanceof Type && o2 instanceof Type) { |
| 372 | return compare(((Type)o1).desc, ((Type)o2).desc); |
| 373 | } |
| 374 | if(o1 instanceof IReferenceTypeDescriptor && o2 instanceof IReferenceTypeDescriptor) { |
| 375 | return ((IReferenceTypeDescriptor)o1).getQualifiedName().compareTo(((IReferenceTypeDescriptor)o2).getQualifiedName()); |
| 376 | } |
| 377 | if(o1 instanceof IMethodDescriptor && o2 instanceof IMethodDescriptor) { |
| 378 | try { |
| 379 | return Signatures.getQualifiedMethodSignature((IMethodDescriptor)o1).compareTo(Signatures.getQualifiedMethodSignature((IMethodDescriptor)o2)); |
| 380 | } |
| 381 | catch(CoreException ce) { |
| 382 | return -1; |
| 383 | } |
| 384 | } |
| 385 | if(o1 instanceof IFieldDescriptor && o2 instanceof IFieldDescriptor) { |
| 386 | try { |
| 387 | return Signatures.getQualifiedFieldSignature((IFieldDescriptor)o1).compareTo(Signatures.getQualifiedFieldSignature((IFieldDescriptor)o2)); |
| 388 | } |
| 389 | catch(CoreException ce) { |
| 390 | return -1; |
| 391 | } |
| 392 | } |
| 393 | if(o1 instanceof IComponentDescriptor && o2 instanceof IComponentDescriptor) { |
| 394 | return ((IComponentDescriptor)o1).getId().compareTo(((IComponentDescriptor)o2).getId()); |
| 395 | } |
| 396 | return -1; |
| 397 | }; |
| 398 | }; |
| 399 | |
| 400 | /** |
| 401 | * Root item describing the use of one component |
| 402 | */ |
| 403 | static class Report { |
| 404 | String name = null; |
| 405 | TreeMap children = new TreeMap(compare); |
| 406 | CountGroup counts = new CountGroup(); |
| 407 | } |
| 408 | |
| 409 | /** |
| 410 | * Describes a type, used to key a collection of {@link Member}s |
| 411 | */ |
| 412 | static class Type { |
| 413 | IElementDescriptor desc = null; |
| 414 | CountGroup counts = new CountGroup(); |
| 415 | public Type(IElementDescriptor desc) { |
| 416 | this.desc = desc; |
| 417 | } |
| 418 | } |
| 419 | |
| 420 | /** |
| 421 | * Describes a member that is being used |
| 422 | */ |
| 423 | static class Member { |
| 424 | IElementDescriptor descriptor = null; |
| 425 | TreeMap children = new TreeMap(compare); |
| 426 | CountGroup counts = new CountGroup(); |
| 427 | public Member(IElementDescriptor desc) { |
| 428 | this.descriptor = desc; |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | /** |
| 433 | * Describes a reference from a given descriptor |
| 434 | */ |
| 435 | static class Reference { |
| 436 | IElementDescriptor desc = null; |
| 437 | int line = -1, vis = -1; |
| 438 | public Reference(IElementDescriptor desc, int line, int vis) { |
| 439 | this.desc = desc; |
| 440 | this.line = line; |
| 441 | this.vis = vis; |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | /** |
| 446 | * A group of counters to origin meta-data |
| 447 | */ |
| 448 | static final class CountGroup { |
| 449 | int total_api_field_count = 0; |
| 450 | int total_private_field_count = 0; |
| 451 | int total_permissable_field_count = 0; |
| 452 | int total_fragment_permissible_field_count = 0; |
| 453 | int total_other_field_count = 0; |
| 454 | int total_api_method_count = 0; |
| 455 | int total_private_method_count = 0; |
| 456 | int total_permissable_method_count = 0; |
| 457 | int total_fragment_permissible_method_count = 0; |
| 458 | int total_other_method_count = 0; |
| 459 | int total_api_type_count = 0; |
| 460 | int total_private_type_count = 0; |
| 461 | int total_permissable_type_count = 0; |
| 462 | int total_fragment_permissible_type_count = 0; |
| 463 | int total_other_type_count = 0; |
| 464 | |
| 465 | public int getTotalRefCount() { |
| 466 | return total_api_field_count + |
| 467 | total_api_method_count + |
| 468 | total_api_type_count + |
| 469 | total_other_field_count + |
| 470 | total_other_method_count + |
| 471 | total_other_type_count + |
| 472 | total_private_field_count + |
| 473 | total_private_method_count + |
| 474 | total_private_type_count + |
| 475 | total_permissable_field_count + |
| 476 | total_permissable_method_count + |
| 477 | total_permissable_type_count + |
| 478 | total_fragment_permissible_field_count + |
| 479 | total_fragment_permissible_method_count + |
| 480 | total_fragment_permissible_type_count; |
| 481 | } |
| 482 | |
| 483 | public int getTotalApiRefCount() { |
| 484 | return total_api_field_count + total_api_method_count + total_api_type_count; |
| 485 | } |
| 486 | |
| 487 | public int getTotalInternalRefCount() { |
| 488 | return total_private_field_count + total_private_method_count + total_private_type_count; |
| 489 | } |
| 490 | |
| 491 | public int getTotalOtherRefCount() { |
| 492 | return total_other_field_count + total_other_method_count + total_other_type_count; |
| 493 | } |
| 494 | |
| 495 | public int getTotalPermissableRefCount() { |
| 496 | return total_permissable_field_count + total_permissable_method_count + total_permissable_type_count; |
| 497 | } |
| 498 | |
| 499 | public int getTotalFragmentPermissibleRefCount() { |
| 500 | return total_fragment_permissible_field_count + total_fragment_permissible_method_count + total_fragment_permissible_type_count; |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | /** |
| 505 | * Handler for parsing the not_searched.xml file to output a summary or |
| 506 | * missing required bundles |
| 507 | */ |
| 508 | static final class MissingHandler extends DefaultHandler { |
| 509 | List missing = new ArrayList(); |
| 510 | static String pattern = "Require-Bundle:"; //$NON-NLS-1$ |
| 511 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { |
| 512 | if(IApiXmlConstants.ELEMENT_COMPONENT.equals(qName)) { |
| 513 | String value = attributes.getValue("details"); //$NON-NLS-1$ |
| 514 | StringTokenizer tokenizer = new StringTokenizer(value, "<>"); //$NON-NLS-1$ |
| 515 | int index = -1; |
| 516 | while(tokenizer.hasMoreTokens()) { |
| 517 | value = tokenizer.nextToken(); |
| 518 | index = value.indexOf(pattern); |
| 519 | if(index > -1) { |
| 520 | missing.add(value.replaceAll(pattern, Util.EMPTY_STRING)); |
| 521 | } |
| 522 | } |
| 523 | } |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | /** |
| 528 | * Visibility constant indicating an element has host-fragment level of visibility. |
| 529 | * i.e. fragments have {@link #PRIVATE_PERMISSIBLE}-like access to the internals of their host. |
| 530 | * |
| 531 | * @since 1.0.1 |
| 532 | */ |
| 533 | public static final int FRAGMENT_PERMISSIBLE = 0x0000005; |
| 534 | /** |
| 535 | * Default XSLT file name |
| 536 | */ |
| 537 | private static final String DEFAULT_XSLT = "/references.xsl"; //$NON-NLS-1$ |
| 538 | /** |
| 539 | * Colour white for normal / permissible references |
| 540 | */ |
| 541 | static final String NORMAL_REFS_COLOUR = "#FFFFFF"; //$NON-NLS-1$ |
| 542 | /** |
| 543 | * Colour red for internal references |
| 544 | */ |
| 545 | static final String INTERNAL_REFS_COLOUR = "#F6CECE"; //$NON-NLS-1$ |
| 546 | /** |
| 547 | * Style HTML bits for a page that shows references |
| 548 | */ |
| 549 | static final String REF_STYLE; |
| 550 | /** |
| 551 | * The script block used to show an expanding table of references |
| 552 | */ |
| 553 | static final String REF_SCRIPT; |
| 554 | |
| 555 | static { |
| 556 | StringBuffer buffer = new StringBuffer(); |
| 557 | buffer.append("<style type=\"text/css\">\n"); //$NON-NLS-1$ |
| 558 | buffer.append("\t.main {\t\tfont-family:Arial, Helvetica, sans-serif;\n\t}\n"); //$NON-NLS-1$ |
| 559 | 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$ |
| 560 | buffer.append("\t.main h4 {\n\t\tbackground-color:#CCCCCC;\n\t\tmargin:0.15em;\n\t}\n"); //$NON-NLS-1$ |
| 561 | 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$ |
| 562 | buffer.append("\ta.typeslnk:hover {\n\t\ttext-decoration:underline;\n\t}\n"); //$NON-NLS-1$ |
| 563 | 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$ |
| 564 | 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$ |
| 565 | buffer.append("</style>\n"); //$NON-NLS-1$ |
| 566 | REF_STYLE = buffer.toString(); |
| 567 | |
| 568 | buffer = new StringBuffer(); |
| 569 | 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$ |
| 570 | 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$ |
| 571 | REF_SCRIPT = buffer.toString(); |
| 572 | } |
| 573 | |
| 574 | /** |
| 575 | * Method used for initializing tracing in the report converter |
| 576 | */ |
| 577 | public static void setDebug(boolean debugValue) { |
| 578 | DEBUG = debugValue || Util.DEBUG; |
| 579 | } |
| 580 | |
| 581 | /** |
| 582 | * Constant used for controlling tracing in the report converter |
| 583 | */ |
| 584 | protected static boolean DEBUG = Util.DEBUG; |
| 585 | |
| 586 | private File htmlRoot = null; |
| 587 | private File reportsRoot = null; |
| 588 | private String xmlLocation = null; |
| 589 | private String htmlLocation = null; |
| 590 | private File htmlIndex = null; |
| 591 | SAXParser parser = null; |
| 592 | private boolean hasmissing = false; |
| 593 | private UseMetadata metadata = null; |
| 594 | Pattern[] filterPatterns = null; |
| 595 | |
| 596 | /** |
| 597 | * Constructor |
| 598 | * @param htmlroot the folder root where the HTML reports should be written |
| 599 | * @param xmlroot the folder root where the current API use scan output is located |
| 600 | * @param patterns array of regular expressions to prune HTML output with |
| 601 | */ |
| 602 | public UseReportConverter(String htmlroot, String xmlroot, String[] patterns) { |
| 603 | this.xmlLocation = xmlroot; |
| 604 | this.htmlLocation = htmlroot; |
| 605 | if(patterns != null) { |
| 606 | ArrayList pats = new ArrayList(patterns.length); |
| 607 | for (int i = 0; i < patterns.length; i++) { |
| 608 | try { |
| 609 | pats.add(Pattern.compile(patterns[i])); |
| 610 | } |
| 611 | catch(PatternSyntaxException pse) { |
| 612 | if(DEBUG) { |
| 613 | System.out.println(NLS.bind(SearchMessages.UseReportConverter_filter_pattern_not_valid, patterns[i])); |
| 614 | System.out.println(pse.getMessage()); |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | if(!pats.isEmpty()) { |
| 619 | this.filterPatterns = (Pattern[]) pats.toArray(new Pattern[pats.size()]); |
| 620 | } |
| 621 | } |
| 622 | } |
| 623 | |
| 624 | /** |
| 625 | * Runs the converter on the given locations |
| 626 | */ |
| 627 | public void convert(String xslt, IProgressMonitor monitor) throws Exception { |
| 628 | if (this.htmlLocation == null) { |
| 629 | return; |
| 630 | } |
| 631 | SubMonitor localmonitor = SubMonitor.convert(monitor, SearchMessages.UseReportConverter_preparing_report_metadata, 8); |
| 632 | try { |
| 633 | localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_html_root); |
| 634 | Util.updateMonitor(localmonitor, 1); |
| 635 | this.htmlRoot = new File(this.htmlLocation); |
| 636 | if (!this.htmlRoot.exists()) { |
| 637 | if (!this.htmlRoot.mkdirs()) { |
| 638 | throw new Exception(NLS.bind(SearchMessages.could_not_create_file, this.htmlLocation)); |
| 639 | } |
| 640 | } |
| 641 | else { |
| 642 | this.htmlRoot.mkdirs(); |
| 643 | } |
| 644 | localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_xml_root); |
| 645 | Util.updateMonitor(localmonitor, 1); |
| 646 | if (this.xmlLocation == null) { |
| 647 | throw new Exception(SearchMessages.missing_xml_files_location); |
| 648 | } |
| 649 | this.reportsRoot = new File(this.xmlLocation); |
| 650 | if (!this.reportsRoot.exists() || !this.reportsRoot.isDirectory()) { |
| 651 | throw new Exception(NLS.bind(SearchMessages.invalid_directory_name, this.xmlLocation)); |
| 652 | } |
| 653 | |
| 654 | localmonitor.setTaskName(SearchMessages.UseReportConverter_preparing_xslt_file); |
| 655 | Util.updateMonitor(localmonitor, 1); |
| 656 | File xsltFile = null; |
| 657 | if(xslt != null) { |
| 658 | // we will use the default XSLT transform from the ant jar when this is null |
| 659 | xsltFile = new File(xslt); |
| 660 | if(!xsltFile.exists() || !xsltFile.isFile()) { |
| 661 | throw new Exception(SearchMessages.UseReportConverter_xslt_file_not_valid); |
| 662 | } |
| 663 | } |
| 664 | long start = 0; |
| 665 | if(DEBUG) { |
| 666 | start = System.currentTimeMillis(); |
| 667 | } |
| 668 | localmonitor.setTaskName(SearchMessages.UseReportConverter_writing_not_searched); |
| 669 | writeMissingBundlesPage(this.htmlRoot); |
| 670 | writeNotSearchedPage(this.htmlRoot); |
| 671 | Util.updateMonitor(localmonitor, 1); |
| 672 | if(DEBUG) { |
| 673 | System.out.println("done in: "+(System.currentTimeMillis()-start)+ " ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 674 | System.out.println("Parsing use scan..."); //$NON-NLS-1$ |
| 675 | start = System.currentTimeMillis(); |
| 676 | } |
| 677 | localmonitor.setTaskName(SearchMessages.UseReportConverter_parsing_use_scan); |
| 678 | UseScanParser parser = new UseScanParser(); |
| 679 | Visitor convertor = new Visitor(); |
| 680 | parser.parse(xmlLocation, localmonitor.newChild(5), convertor); |
| 681 | Util.updateMonitor(localmonitor, 1); |
| 682 | if(DEBUG) { |
| 683 | System.out.println("done in: "+(System.currentTimeMillis()-start)+ " ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 684 | System.out.println("Sorting reports and writing index..."); //$NON-NLS-1$ |
| 685 | start = System.currentTimeMillis(); |
| 686 | } |
| 687 | localmonitor.setTaskName(SearchMessages.UseReportConverter_writing_root_index); |
| 688 | Collections.sort(convertor.reports, new Comparator() { |
| 689 | public int compare(Object o1, Object o2) { |
| 690 | return ((Report)o1).name.compareTo(((Report)o2).name); |
| 691 | } |
| 692 | }); |
| 693 | writeIndexPage(convertor.reports, this.htmlRoot); |
| 694 | Util.updateMonitor(localmonitor, 1); |
| 695 | if(DEBUG) { |
| 696 | System.out.println("done in: "+(System.currentTimeMillis()-start)+ " ms"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 697 | } |
| 698 | writeMetaPage(this.htmlRoot); |
| 699 | } |
| 700 | finally { |
| 701 | if(localmonitor != null) { |
| 702 | localmonitor.done(); |
| 703 | } |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | /** |
| 708 | * Returns the handle to the default parser, caches the handle once it has been created |
| 709 | * @return the handle to the default parser |
| 710 | * @throws Exception forwarded general exception that can be trapped in Ant builds |
| 711 | */ |
| 712 | SAXParser getParser() throws Exception { |
| 713 | if(this.parser == null) { |
| 714 | SAXParserFactory factory = SAXParserFactory.newInstance(); |
| 715 | try { |
| 716 | this.parser = factory.newSAXParser(); |
| 717 | } catch (ParserConfigurationException pce) { |
| 718 | throw new Exception(SearchMessages.UseReportConverter_pce_error_getting_parser, pce); |
| 719 | } catch (SAXException se) { |
| 720 | throw new Exception(SearchMessages.UseReportConverter_se_error_parser_handle, se); |
| 721 | } |
| 722 | if (this.parser == null) { |
| 723 | throw new Exception(SearchMessages.could_not_create_sax_parser); |
| 724 | } |
| 725 | } |
| 726 | return this.parser; |
| 727 | } |
| 728 | |
| 729 | /** |
| 730 | * Builds the name for the component |
| 731 | * @param id |
| 732 | * @param version |
| 733 | * @return |
| 734 | */ |
| 735 | protected String composeName(String id, String version) { |
| 736 | StringBuffer buffer = new StringBuffer(3+id.length()+version.length()); |
| 737 | buffer.append(id).append(" (").append(version).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 738 | return buffer.toString(); |
| 739 | } |
| 740 | |
| 741 | /** |
| 742 | * @return the index.html file created from the report conversion or <code>null</code> |
| 743 | * if the conversion failed |
| 744 | */ |
| 745 | public File getReportIndex() { |
| 746 | return htmlIndex; |
| 747 | } |
| 748 | |
| 749 | /** |
| 750 | * Applies the given XSLT to the given XML to produce HTML in the given file |
| 751 | * @param xsltfile |
| 752 | * @param xmlfile |
| 753 | * @param htmloutput |
| 754 | * @throws TransformerException |
| 755 | */ |
| 756 | protected void applyXSLT(File xsltFile, File xmlfile, File htmloutput) throws TransformerException, Exception { |
| 757 | Source xslt = null; |
| 758 | if (xsltFile != null) { |
| 759 | xslt = new StreamSource(xsltFile); |
| 760 | } else { |
| 761 | InputStream defaultXsltInputStream = UseReportConverter.class.getResourceAsStream(DEFAULT_XSLT); |
| 762 | if (defaultXsltInputStream != null) { |
| 763 | xslt = new StreamSource(new BufferedInputStream(defaultXsltInputStream)); |
| 764 | } |
| 765 | } |
| 766 | if(xslt == null) { |
| 767 | throw new Exception(SearchMessages.UseReportConverter_no_xstl_specified); |
| 768 | } |
| 769 | applyXSLT(xslt, xmlfile, htmloutput); |
| 770 | } |
| 771 | |
| 772 | /** |
| 773 | * Applies the given XSLT source to the given XML file outputting to the given HTML file |
| 774 | * @param xslt |
| 775 | * @param xmlfile |
| 776 | * @param htmlfile |
| 777 | * @throws TransformerException |
| 778 | */ |
| 779 | protected void applyXSLT(Source xslt, File xmlfile, File htmlfile) throws TransformerException { |
| 780 | Source xml = new StreamSource(xmlfile); |
| 781 | Result html = new StreamResult(htmlfile); |
| 782 | TransformerFactory factory = TransformerFactory.newInstance(); |
| 783 | Transformer former = factory.newTransformer(xslt); |
| 784 | former.transform(xml, html); |
| 785 | } |
| 786 | |
| 787 | /** |
| 788 | * Transforms the given set of xml files with the given XSLT and places the result into a |
| 789 | * corresponding HTML file |
| 790 | * @param xmlfiles |
| 791 | * @param xsltFile |
| 792 | * @param html |
| 793 | */ |
| 794 | protected void tranformXml(File[] xmlfiles, File xsltFile) { |
| 795 | File html = null; |
| 796 | for (int i = 0; i < xmlfiles.length; i++) { |
| 797 | try { |
| 798 | File htmlroot = new File(this.htmlLocation, getHTMLFileLocation(this.reportsRoot, xmlfiles[i])); |
| 799 | if(!htmlroot.exists()) { |
| 800 | htmlroot.mkdirs(); |
| 801 | } |
| 802 | html = new File(getNameFromXMLFilename(xmlfiles[i])); |
| 803 | applyXSLT(xsltFile, xmlfiles[i], html); |
| 804 | } |
| 805 | catch(TransformerException te) {} |
| 806 | catch (Exception e) { |
| 807 | ApiPlugin.log(e); |
| 808 | } |
| 809 | } |
| 810 | } |
| 811 | |
| 812 | /** |
| 813 | * Gets the HTML path to write out the transformed XML file to |
| 814 | * @param reportroot |
| 815 | * @param xmlfile |
| 816 | * @return |
| 817 | */ |
| 818 | protected String getHTMLFileLocation(File reportroot, File xmlfile) { |
| 819 | IPath xml = new Path(xmlfile.getPath()); |
| 820 | IPath report = new Path(reportroot.getPath()); |
| 821 | int segments = xml.matchingFirstSegments(report); |
| 822 | if(segments > 0) { |
| 823 | if(xml.getDevice() != null) { |
| 824 | xml = xml.setDevice(null); |
| 825 | } |
| 826 | IPath html = xml.removeFirstSegments(segments); |
| 827 | return html.removeLastSegments(1).toOSString(); |
| 828 | } |
| 829 | return null; |
| 830 | } |
| 831 | |
| 832 | /** |
| 833 | * Returns the name to use for the corresponding HTML file |
| 834 | * from the given XML file |
| 835 | * @param xmlFile |
| 836 | * @return the HTML name to use |
| 837 | */ |
| 838 | protected String getNameFromXMLFilename(File xmlFile) { |
| 839 | String fileName = xmlFile.getAbsolutePath(); |
| 840 | int index = fileName.lastIndexOf('.'); |
| 841 | StringBuffer buffer = new StringBuffer(); |
| 842 | buffer.append(fileName.substring(this.reportsRoot.getAbsolutePath().length(), index)).append(HTML_EXTENSION); |
| 843 | File htmlFile = new File(this.htmlLocation, String.valueOf(buffer)); |
| 844 | return htmlFile.getAbsolutePath(); |
| 845 | } |
| 846 | |
| 847 | /** |
| 848 | * Returns the collection of missing bundle names |
| 849 | * @param missingfile |
| 850 | * @return the collection of missing bundle names |
| 851 | * @throws Exception |
| 852 | */ |
| 853 | protected String[] getMissingBundles(File missingfile) throws Exception { |
| 854 | MissingHandler handler = new MissingHandler(); |
| 855 | getParser().parse(missingfile, handler); |
| 856 | return (String[]) handler.missing.toArray(new String[handler.missing.size()]); |
| 857 | } |
| 858 | |
| 859 | /** |
| 860 | * Returns the sentence describing the purpose / reason of the missing bundles |
| 861 | * @return a blurb describing the table of missing bundles |
| 862 | */ |
| 863 | protected String getMissingBundlesHeader() { |
| 864 | return SearchMessages.UseReportConverter_reported_missing_bundles; |
| 865 | } |
| 866 | |
| 867 | /** |
| 868 | * Writes any existing metadata out to a meta.html file in the root of the |
| 869 | * HTML report location |
| 870 | * @param htmlroot |
| 871 | * @throws Exception |
| 872 | */ |
| 873 | void writeMetaPage(File htmlroot) throws Exception { |
| 874 | File meta = null; |
| 875 | PrintWriter writer = null; |
| 876 | try { |
| 877 | File file = new File(this.reportsRoot, "meta.xml"); //$NON-NLS-1$ |
| 878 | if(!file.exists()) { |
| 879 | //do nothing if no meta.xml file |
| 880 | return; |
| 881 | } |
| 882 | String filename = "meta"; //$NON-NLS-1$ |
| 883 | meta = new File(htmlroot, filename+HTML_EXTENSION); |
| 884 | if(!meta.exists()) { |
| 885 | meta.createNewFile(); |
| 886 | } |
| 887 | StringBuffer buffer = new StringBuffer(); |
| 888 | buffer.append(HTML_HEADER); |
| 889 | buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META); |
| 890 | buffer.append(OPEN_TITLE).append(SearchMessages.UseReportConverter_use_scan_info).append(CLOSE_TITLE); |
| 891 | buffer.append(CLOSE_HEAD); |
| 892 | buffer.append(OPEN_BODY); |
| 893 | buffer.append(OPEN_H3).append(SearchMessages.UseReportConverter_use_scan_info).append(CLOSE_H3); |
| 894 | writeMetadataSummary(buffer); |
| 895 | buffer.append(W3C_FOOTER); |
| 896 | |
| 897 | //write file |
| 898 | FileWriter fileWriter = new FileWriter(meta); |
| 899 | writer = new PrintWriter(new BufferedWriter(fileWriter)); |
| 900 | writer.println(buffer.toString()); |
| 901 | writer.flush(); |
| 902 | } |
| 903 | catch(IOException ioe) { |
| 904 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, meta.getAbsolutePath())); |
| 905 | } |
| 906 | finally { |
| 907 | if(writer != null) { |
| 908 | writer.close(); |
| 909 | } |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | /** |
| 914 | * Writes out a summary of the missing required bundles |
| 915 | * @param htmlroot |
| 916 | */ |
| 917 | protected void writeMissingBundlesPage(final File htmlroot) throws Exception { |
| 918 | File missing = null; |
| 919 | PrintWriter writer = null; |
| 920 | try { |
| 921 | String filename = "missing"; //$NON-NLS-1$ |
| 922 | missing = new File(htmlroot, filename+HTML_EXTENSION); |
| 923 | if(!missing.exists()) { |
| 924 | missing.createNewFile(); |
| 925 | } |
| 926 | |
| 927 | File file = new File(this.reportsRoot, "not_searched.xml"); //$NON-NLS-1$ |
| 928 | TreeSet sorted = new TreeSet(Util.componentsorter); |
| 929 | if (file.exists()) { |
| 930 | String[] missingBundles = getMissingBundles(file); |
| 931 | this.hasmissing = missingBundles.length > 0; |
| 932 | for (int i = 0; i < missingBundles.length; i++) { |
| 933 | sorted.add(missingBundles[i]); |
| 934 | } |
| 935 | } |
| 936 | StringBuffer buffer = new StringBuffer(); |
| 937 | buffer.append(HTML_HEADER); |
| 938 | buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META); |
| 939 | buffer.append(OPEN_TITLE).append(SearchMessages.UseReportConverter_missing_required).append(CLOSE_TITLE); |
| 940 | buffer.append(CLOSE_HEAD); |
| 941 | buffer.append(OPEN_BODY); |
| 942 | buffer.append(OPEN_H3).append(SearchMessages.UseReportConverter_missing_required).append(CLOSE_H3); |
| 943 | |
| 944 | if(sorted.isEmpty()) { |
| 945 | buffer.append(SearchMessages.UseReportConverter_no_required_missing).append(BR); |
| 946 | } |
| 947 | else { |
| 948 | buffer.append(OPEN_P).append(getMissingBundlesHeader()).append(CLOSE_P); |
| 949 | buffer.append("<table border=\"1\" width=\"50%\">\n"); //$NON-NLS-1$ |
| 950 | buffer.append(OPEN_TR).append("<td bgcolor=\"#CC9933\" width=\"36%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_required_bundles).append(CLOSE_B).append(CLOSE_TD).append(CLOSE_TR); //$NON-NLS-1$ |
| 951 | } |
| 952 | String value = null; |
| 953 | for (Iterator iter = sorted.iterator(); iter.hasNext();) { |
| 954 | value = (String) iter.next(); |
| 955 | buffer.append(OPEN_TR).append(OPEN_TD).append(value).append(CLOSE_TD).append(CLOSE_TR); |
| 956 | } |
| 957 | buffer.append(CLOSE_TABLE); |
| 958 | buffer.append(BR).append("<a href=\"not_searched.html\">").append(SearchMessages.UseReportConverter_back_to_not_searched).append(CLOSE_A); //$NON-NLS-1$ |
| 959 | buffer.append(W3C_FOOTER); |
| 960 | |
| 961 | //write file |
| 962 | FileWriter fileWriter = new FileWriter(missing); |
| 963 | writer = new PrintWriter(new BufferedWriter(fileWriter)); |
| 964 | writer.println(buffer.toString()); |
| 965 | writer.flush(); |
| 966 | } |
| 967 | catch(IOException ioe) { |
| 968 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, missing.getAbsolutePath())); |
| 969 | } |
| 970 | finally { |
| 971 | if(writer != null) { |
| 972 | writer.close(); |
| 973 | } |
| 974 | } |
| 975 | } |
| 976 | |
| 977 | /** |
| 978 | * Writes out the file of components that were not searched: either because they appeared in an exclude list |
| 979 | * or they have no .api_description file |
| 980 | * |
| 981 | * @param htmlroot |
| 982 | */ |
| 983 | void writeNotSearchedPage(final File htmlroot) throws Exception { |
| 984 | File originhtml = null; |
| 985 | try { |
| 986 | String filename = "not_searched"; //$NON-NLS-1$ |
| 987 | originhtml = new File(htmlroot, filename+HTML_EXTENSION); |
| 988 | if(!originhtml.exists()) { |
| 989 | originhtml.createNewFile(); |
| 990 | } |
| 991 | File xml = new File(this.reportsRoot, filename+XML_EXTENSION); |
| 992 | InputStream defaultXsltInputStream = UseReportConverter.class.getResourceAsStream(getNotSearchedXSLPath()); |
| 993 | Source xslt = null; |
| 994 | if (defaultXsltInputStream != null) { |
| 995 | xslt = new StreamSource(new BufferedInputStream(defaultXsltInputStream)); |
| 996 | } |
| 997 | if(xslt == null) { |
| 998 | throw new Exception(SearchMessages.UseReportConverter_no_xstl_specified); |
| 999 | } |
| 1000 | if (xml.exists()) { |
| 1001 | applyXSLT(xslt, xml, originhtml); |
| 1002 | } |
| 1003 | } |
| 1004 | catch(IOException ioe) { |
| 1005 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, originhtml.getAbsolutePath())); |
| 1006 | } |
| 1007 | catch (TransformerException te) { |
| 1008 | throw new Exception(SearchMessages.UseReportConverter_te_applying_xslt_skipped, te); |
| 1009 | } |
| 1010 | catch (CoreException e) { |
| 1011 | throw new Exception(NLS.bind(SearchMessages.UseReportConverter_coreexception_writing_html_file, originhtml.getAbsolutePath())); |
| 1012 | } |
| 1013 | } |
| 1014 | |
| 1015 | /** |
| 1016 | * Returns path of XSL file to use when generating "not searched" information. |
| 1017 | * |
| 1018 | * @return path to the XSL file |
| 1019 | */ |
| 1020 | String getNotSearchedXSLPath() { |
| 1021 | return "/notsearched.xsl"; //$NON-NLS-1$ |
| 1022 | } |
| 1023 | |
| 1024 | /** |
| 1025 | * Writes the referenced member index page |
| 1026 | * @param report |
| 1027 | * @param referees the listing of referencing bundles |
| 1028 | */ |
| 1029 | void writeReferencedMemberPage(final Report report, final List referees) throws Exception { |
| 1030 | PrintWriter writer = null; |
| 1031 | File originhtml = null; |
| 1032 | try { |
| 1033 | File htmlroot = new File(this.htmlLocation, report.name); |
| 1034 | if(!htmlroot.exists()) { |
| 1035 | htmlroot.mkdirs(); |
| 1036 | } |
| 1037 | originhtml = new File(htmlroot, "index.html"); //$NON-NLS-1$ |
| 1038 | if(!originhtml.exists()) { |
| 1039 | originhtml.createNewFile(); |
| 1040 | } |
| 1041 | StringBuffer buffer = new StringBuffer(); |
| 1042 | buffer.append(HTML_HEADER); |
| 1043 | buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META); |
| 1044 | buffer.append(REF_STYLE); |
| 1045 | buffer.append(REF_SCRIPT); |
| 1046 | buffer.append(OPEN_TITLE).append(getReferencedTypeTitle(report.name)).append(CLOSE_TITLE); |
| 1047 | buffer.append(CLOSE_HEAD); |
| 1048 | buffer.append(OPEN_BODY); |
| 1049 | buffer.append(OPEN_H3).append(getReferencedTypeHeader(report.name)).append(CLOSE_H3); |
| 1050 | 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$ |
| 1051 | String additional = getAdditionalReferencedTypeInformation(); |
| 1052 | if(additional != null) { |
| 1053 | buffer.append(additional); |
| 1054 | } |
| 1055 | buffer.append(getReferencesTableHeader(SearchMessages.UseReportConverter_referenced_type)); |
| 1056 | CountGroup counts = null; |
| 1057 | String link = null; |
| 1058 | Entry entry = null; |
| 1059 | File typefile = null; |
| 1060 | TreeMap map = null; |
| 1061 | Type type = null; |
| 1062 | for (Iterator iter = report.children.entrySet().iterator(); iter.hasNext();) { |
| 1063 | entry = (Entry) iter.next(); |
| 1064 | map = (TreeMap) entry.getValue(); |
| 1065 | type = (Type) entry.getKey(); |
| 1066 | counts = type.counts; |
| 1067 | |
| 1068 | String fqname = Signatures.getQualifiedTypeSignature((IReferenceTypeDescriptor) type.desc); |
| 1069 | typefile = new File(htmlroot, fqname+HTML_EXTENSION); |
| 1070 | if(!typefile.exists()) { |
| 1071 | typefile.createNewFile(); |
| 1072 | } |
| 1073 | link = extractLinkFrom(htmlroot, typefile.getAbsolutePath()); |
| 1074 | buffer.append(getReferenceTableEntry(counts, link, fqname)); |
| 1075 | writeTypePage(map, type, typefile, fqname); |
| 1076 | } |
| 1077 | buffer.append(CLOSE_TABLE); |
| 1078 | buffer.append(BR); |
| 1079 | buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_referencing_bundles).append(CLOSE_H4); |
| 1080 | buffer.append(OPEN_P).append(NLS.bind(SearchMessages.UseReportConverter_following_bundles_have_refs, report.name)).append(CLOSE_P); |
| 1081 | buffer.append("<a name=\"bundles\">").append(CLOSE_A); //$NON-NLS-1$ |
| 1082 | buffer.append("<table border=\"1\" width=\"70%\">\n"); //$NON-NLS-1$ |
| 1083 | buffer.append(OPEN_TR); |
| 1084 | buffer.append("\t<td bgcolor=\"#CC9933\" width=\"70%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_bundle).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1085 | buffer.append("\t<td bgcolor=\"#CC9933\" width=\"14%\" align=\"center\">").append(OPEN_B).append(SearchMessages.UseReportConverter_version).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1086 | buffer.append("\t<td bgcolor=\"#CC9933\" width=\"36%\" align=\"center\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_count).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1087 | buffer.append(CLOSE_TR); |
| 1088 | Collections.sort(referees, compare); |
| 1089 | IComponentDescriptor comp = null; |
| 1090 | for (int i = 0; i < referees.size(); i++) { |
| 1091 | type = (Type) referees.get(i); |
| 1092 | comp = (IComponentDescriptor) type.desc; |
| 1093 | buffer.append("<tr bgcolor=\"").append((type.counts.getTotalInternalRefCount() > 0 ? INTERNAL_REFS_COLOUR : NORMAL_REFS_COLOUR)).append("\">\n"); //$NON-NLS-1$//$NON-NLS-2$ |
| 1094 | buffer.append("\t").append(OPEN_TD).append(comp.getId()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1095 | buffer.append("\t").append(OPEN_TD).append(comp.getVersion()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1096 | buffer.append("\t<td align=\"center\">").append(type.counts.getTotalRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1097 | buffer.append(CLOSE_TR); |
| 1098 | } |
| 1099 | buffer.append(CLOSE_TABLE); |
| 1100 | 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$ |
| 1101 | buffer.append(W3C_FOOTER); |
| 1102 | |
| 1103 | FileWriter fileWriter = new FileWriter(originhtml); |
| 1104 | writer = new PrintWriter(new BufferedWriter(fileWriter)); |
| 1105 | writer.println(buffer.toString()); |
| 1106 | writer.flush(); |
| 1107 | } |
| 1108 | catch(IOException ioe) { |
| 1109 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, originhtml.getAbsolutePath())); |
| 1110 | } |
| 1111 | finally { |
| 1112 | if (writer != null) { |
| 1113 | writer.close(); |
| 1114 | } |
| 1115 | } |
| 1116 | } |
| 1117 | |
| 1118 | /** |
| 1119 | * Returns a string of additional information to print out at the top of the referenced types page. |
| 1120 | * @return additional referenced type information. |
| 1121 | */ |
| 1122 | protected String getAdditionalReferencedTypeInformation() { |
| 1123 | return null; |
| 1124 | } |
| 1125 | |
| 1126 | /** |
| 1127 | * Returns the page title to use for the referenced types page |
| 1128 | * @param bundle |
| 1129 | * @return the page title for the referenced types page |
| 1130 | */ |
| 1131 | protected String getReferencedTypeTitle(String bundle) { |
| 1132 | return NLS.bind(SearchMessages.UseReportConverter_types_used_in, bundle); |
| 1133 | } |
| 1134 | |
| 1135 | /** |
| 1136 | * Returns the header title to use for the reference types page. This header |
| 1137 | * is the first header on the top of the page. |
| 1138 | * @param bundle |
| 1139 | * @return the header title for the referenced types page |
| 1140 | */ |
| 1141 | protected String getReferencedTypeHeader(String bundle) { |
| 1142 | return NLS.bind(SearchMessages.UseReportConverter_types_used_in, bundle); |
| 1143 | } |
| 1144 | |
| 1145 | /** |
| 1146 | * Writes the page that displays all of the members used in a type |
| 1147 | * @param map |
| 1148 | * @param type |
| 1149 | * @param typefile |
| 1150 | * @param typename |
| 1151 | * @throws Exception |
| 1152 | */ |
| 1153 | void writeTypePage(TreeMap map, Type type, File typefile, String typename) throws Exception { |
| 1154 | PrintWriter writer = null; |
| 1155 | try { |
| 1156 | StringBuffer buffer = new StringBuffer(); |
| 1157 | buffer.append(HTML_HEADER); |
| 1158 | buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META); |
| 1159 | buffer.append(REF_STYLE); |
| 1160 | buffer.append(REF_SCRIPT); |
| 1161 | buffer.append(OPEN_TITLE).append(getTypeTitle(typename)).append(CLOSE_TITLE); |
| 1162 | buffer.append(CLOSE_HEAD); |
| 1163 | buffer.append(OPEN_BODY); |
| 1164 | buffer.append(OPEN_H3).append(getTypeHeader(typename)).append(CLOSE_H3); |
| 1165 | buffer.append(getTypeCountSummary(typename, type.counts, map.size())); |
| 1166 | buffer.append(OPEN_H4).append(getTypeDetailsHeader()).append(CLOSE_H4); |
| 1167 | buffer.append("<table width=\"50%\" border=\"1\">\n"); //$NON-NLS-1$ |
| 1168 | buffer.append(OPEN_P).append(getTypeDetails()).append(CLOSE_P); |
| 1169 | buffer.append("<div align=\"left\" class=\"main\">"); //$NON-NLS-1$ |
| 1170 | buffer.append("<table border=\"1\" width=\"70%\">\n"); //$NON-NLS-1$ |
| 1171 | buffer.append(OPEN_TR); |
| 1172 | buffer.append("<td bgcolor=\"#CC9933\">").append(OPEN_B).append(SearchMessages.UseReportConverter_member).append("</b></td>\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1173 | buffer.append(CLOSE_TR); |
| 1174 | Entry entry = null; |
| 1175 | IElementDescriptor desc = null; |
| 1176 | Member mem = null; |
| 1177 | for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { |
| 1178 | entry = (Entry) iter.next(); |
| 1179 | desc = (IElementDescriptor)entry.getKey(); |
| 1180 | mem = (Member) entry.getValue(); |
| 1181 | buffer.append(OPEN_TR); |
| 1182 | buffer.append("<td align=\"left\">\n"); //$NON-NLS-1$ |
| 1183 | buffer.append(OPEN_B); |
| 1184 | buffer.append("<a href=\"javascript:void(0)\" class=\"typeslnk\" onclick=\"expand(this)\">\n"); //$NON-NLS-1$ |
| 1185 | buffer.append("<span>[+] </span>").append(getDisplayName(desc, false)).append("\n"); //$NON-NLS-1$//$NON-NLS-2$ |
| 1186 | buffer.append(CLOSE_A).append(CLOSE_B); |
| 1187 | buffer.append(getReferencesTable(mem)).append("\n"); //$NON-NLS-1$ |
| 1188 | buffer.append(CLOSE_TR); |
| 1189 | } |
| 1190 | buffer.append(CLOSE_TABLE); |
| 1191 | buffer.append(CLOSE_DIV); |
| 1192 | 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$ |
| 1193 | buffer.append(W3C_FOOTER); |
| 1194 | |
| 1195 | //write the file |
| 1196 | FileWriter fileWriter = new FileWriter(typefile); |
| 1197 | writer = new PrintWriter(new BufferedWriter(fileWriter)); |
| 1198 | writer.print(buffer.toString()); |
| 1199 | writer.flush(); |
| 1200 | } |
| 1201 | catch(IOException ioe) { |
| 1202 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, typefile.getAbsolutePath())); |
| 1203 | } |
| 1204 | finally { |
| 1205 | if(writer != null) { |
| 1206 | writer.close(); |
| 1207 | } |
| 1208 | } |
| 1209 | } |
| 1210 | |
| 1211 | /** |
| 1212 | * Returns the header to use for the section that describes the type details table |
| 1213 | * @return the details header |
| 1214 | */ |
| 1215 | protected String getTypeDetailsHeader() { |
| 1216 | return SearchMessages.UseReportConverter_reference_details; |
| 1217 | } |
| 1218 | |
| 1219 | /** |
| 1220 | * Returns the blurb that follows the type details header |
| 1221 | * @return the details information |
| 1222 | * @see #getTypeDetailsHeader() |
| 1223 | */ |
| 1224 | protected String getTypeDetails() { |
| 1225 | return SearchMessages.UseReportConverter_click_an_entry_to_see_details; |
| 1226 | } |
| 1227 | |
| 1228 | /** |
| 1229 | * Returns the title to use for the type references page |
| 1230 | * @param typename |
| 1231 | * @return the type references page title |
| 1232 | */ |
| 1233 | protected String getTypeTitle(String typename) { |
| 1234 | return NLS.bind(SearchMessages.UseReportConverter_usage_details, Signature.getSimpleName(typename)); |
| 1235 | } |
| 1236 | |
| 1237 | /** |
| 1238 | * Returns the header to use for the types page. This is the first header on the page |
| 1239 | * @param typename |
| 1240 | * @return the type page header |
| 1241 | */ |
| 1242 | protected String getTypeHeader(String typename) { |
| 1243 | return NLS.bind(SearchMessages.UseReportConverter_usage_details, Signature.getSimpleName(typename)); |
| 1244 | } |
| 1245 | |
| 1246 | /** |
| 1247 | * Returns the nested table of references |
| 1248 | * @return the nested table of references as a string |
| 1249 | */ |
| 1250 | String getReferencesTable(Member member) { |
| 1251 | StringBuffer buffer = new StringBuffer(); |
| 1252 | Entry entry = null; |
| 1253 | buffer.append("<div colspan=\"6\" class=\"types\">\n"); //$NON-NLS-1$ |
| 1254 | buffer.append("<table width=\"100%\" border=\"0\">\n"); //$NON-NLS-1$ |
| 1255 | ArrayList refs = null; |
| 1256 | Reference ref = null; |
| 1257 | for (Iterator iter = member.children.entrySet().iterator(); iter.hasNext();) { |
| 1258 | entry = (Entry) iter.next(); |
| 1259 | buffer.append("<tr align=\"left\"> \n"); //$NON-NLS-1$ |
| 1260 | buffer.append("<td colspan=\"3\" bgcolor=\"#CCCCCC\">").append(OPEN_B).append(entry.getKey()).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1261 | buffer.append(CLOSE_TR); |
| 1262 | buffer.append("<tr bgcolor=\"#CC9933\">"); //$NON-NLS-1$ |
| 1263 | buffer.append("<td align=\"left\" width=\"92%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_location).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1264 | buffer.append("<td align=\"center\" width=\"8%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_line_number).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1265 | buffer.append("<td align=\"center\" width=\"8%\">").append(OPEN_B).append(SearchMessages.UseReportConverter_reference_kind).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1266 | buffer.append(CLOSE_TR); |
| 1267 | refs = (ArrayList) entry.getValue(); |
| 1268 | Collections.sort(refs, compare); |
| 1269 | for (Iterator iter2 = refs.iterator(); iter2.hasNext();) { |
| 1270 | ref = (Reference) iter2.next(); |
| 1271 | try { |
| 1272 | String name = getDisplayName(ref.desc, true); |
| 1273 | buffer.append(OPEN_TR); |
| 1274 | buffer.append(OPEN_TD).append(name).append(CLOSE_TD); |
| 1275 | buffer.append("<td align=\"center\">").append(ref.line).append(CLOSE_TD); //$NON-NLS-1$ |
| 1276 | buffer.append("<td align=\"center\">").append(VisibilityModifiers.getVisibilityName(ref.vis)).append(CLOSE_TD); //$NON-NLS-1$ |
| 1277 | buffer.append(CLOSE_TR); |
| 1278 | } |
| 1279 | catch(CoreException ce) { |
| 1280 | ApiPlugin.log(ce); |
| 1281 | } |
| 1282 | } |
| 1283 | } |
| 1284 | buffer.append(CLOSE_TABLE); |
| 1285 | buffer.append(CLOSE_DIV); |
| 1286 | return buffer.toString(); |
| 1287 | } |
| 1288 | |
| 1289 | /** |
| 1290 | * Returns the name to display for the given {@link IElementDescriptor} which can be qualified or not |
| 1291 | * @param desc |
| 1292 | * @param qualified |
| 1293 | * @return the (un)-qualified name to display for the given {@link IElementDescriptor} |
| 1294 | * @throws CoreException |
| 1295 | */ |
| 1296 | String getDisplayName(IElementDescriptor desc, boolean qualified) throws CoreException { |
| 1297 | String displayname = null; |
| 1298 | switch(desc.getElementType()) { |
| 1299 | case IElementDescriptor.TYPE: { |
| 1300 | IReferenceTypeDescriptor rtype = (IReferenceTypeDescriptor) desc; |
| 1301 | displayname = Signatures.getTypeSignature(rtype.getSignature(), rtype.getGenericSignature(), qualified); |
| 1302 | break; |
| 1303 | } |
| 1304 | case IElementDescriptor.METHOD: { |
| 1305 | IMethodDescriptor method = (IMethodDescriptor)desc; |
| 1306 | if(qualified) { |
| 1307 | displayname = Signatures.getQualifiedMethodSignature(method); |
| 1308 | } |
| 1309 | else { |
| 1310 | displayname = Signatures.getMethodSignature(method); |
| 1311 | } |
| 1312 | break; |
| 1313 | } |
| 1314 | case IElementDescriptor.FIELD: { |
| 1315 | IFieldDescriptor field = (IFieldDescriptor) desc; |
| 1316 | if(qualified) { |
| 1317 | displayname = Signatures.getQualifiedFieldSignature(field); |
| 1318 | } |
| 1319 | else { |
| 1320 | displayname = field.getName(); |
| 1321 | } |
| 1322 | break; |
| 1323 | } |
| 1324 | } |
| 1325 | return displayname; |
| 1326 | } |
| 1327 | |
| 1328 | /** |
| 1329 | * Extracts underlying link text from the given absolute filename based off the root file |
| 1330 | * @param root |
| 1331 | * @param fileName |
| 1332 | * @return link text pruned via the given root file |
| 1333 | */ |
| 1334 | String extractLinkFrom(File root, String fileName) { |
| 1335 | StringBuffer buffer = new StringBuffer(); |
| 1336 | String substring = fileName.substring(root.getAbsolutePath().length()).replace('\\', '/'); |
| 1337 | buffer.append('.'); |
| 1338 | if(substring.charAt(0) != '/') { |
| 1339 | buffer.append('/'); |
| 1340 | } |
| 1341 | buffer.append(substring); |
| 1342 | return String.valueOf(buffer); |
| 1343 | } |
| 1344 | |
| 1345 | /** |
| 1346 | * Returns the page title for the index page |
| 1347 | * @return the index page title |
| 1348 | */ |
| 1349 | protected String getIndexTitle() { |
| 1350 | return SearchMessages.UseReportConverter_bundle_usage_information; |
| 1351 | } |
| 1352 | |
| 1353 | /** |
| 1354 | * Returns the main header for the index page, this header appears as the first header for the page |
| 1355 | * @return the index page header |
| 1356 | */ |
| 1357 | protected String getIndexHeader() { |
| 1358 | return SearchMessages.UseReportConverter_bundle_usage_information; |
| 1359 | } |
| 1360 | |
| 1361 | /** |
| 1362 | * Writes the main index file for the reports |
| 1363 | * @param reportsRoot |
| 1364 | */ |
| 1365 | void writeIndexPage(List sortedreports, File reportsRoot) throws Exception { |
| 1366 | PrintWriter writer = null; |
| 1367 | try { |
| 1368 | htmlIndex = new File(this.htmlLocation, "index.html"); //$NON-NLS-1$ |
| 1369 | if(!htmlIndex.exists()) { |
| 1370 | htmlIndex.createNewFile(); |
| 1371 | } |
| 1372 | StringBuffer buffer = new StringBuffer(); |
| 1373 | buffer.append(HTML_HEADER); |
| 1374 | buffer.append(OPEN_HTML).append(OPEN_HEAD).append(CONTENT_TYPE_META); |
| 1375 | writeMetadataHeaders(buffer); |
| 1376 | buffer.append(OPEN_TITLE).append(getIndexTitle()).append(CLOSE_TITLE); |
| 1377 | buffer.append(CLOSE_HEAD); |
| 1378 | buffer.append(OPEN_BODY); |
| 1379 | buffer.append(OPEN_H3).append(getIndexHeader()).append(CLOSE_H3); |
| 1380 | writeMetadataSummary(buffer); |
| 1381 | buffer.append(OPEN_H4).append(SearchMessages.UseReportConvertor_additional_infos_section).append(CLOSE_H4); |
| 1382 | if(this.hasmissing) { |
| 1383 | buffer.append(OPEN_P); |
| 1384 | buffer.append(NLS.bind(SearchMessages.UseReportConverter_missing_bundles_prevented_scan, |
| 1385 | new String[] {" <a href=\"./missing.html\">", "</a>"})); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1386 | buffer.append(CLOSE_P); |
| 1387 | } |
| 1388 | buffer.append(OPEN_P); |
| 1389 | buffer.append(NLS.bind(SearchMessages.UseReportConverter_bundles_that_were_not_searched, new String[] {"<a href=\"./not_searched.html\">", "</a></p>\n"})); //$NON-NLS-1$//$NON-NLS-2$ |
| 1390 | String additional = getAdditionalIndexInfo(sortedreports.size() > 0); |
| 1391 | if(additional != null) { |
| 1392 | buffer.append(additional); |
| 1393 | } |
| 1394 | if(sortedreports.size() > 0) { |
| 1395 | buffer.append(OPEN_P).append(SearchMessages.UseReportConverter_inlined_description).append(CLOSE_P); |
| 1396 | buffer.append(getReferencesTableHeader(SearchMessages.UseReportConverter_bundle)); |
| 1397 | if(sortedreports.size() > 0) { |
| 1398 | Report report = null; |
| 1399 | File refereehtml = null; |
| 1400 | String link = null; |
| 1401 | for(Iterator iter = sortedreports.iterator(); iter.hasNext();) { |
| 1402 | report = (Report) iter.next(); |
| 1403 | if(report != null) { |
| 1404 | refereehtml = new File(this.reportsRoot, report.name+File.separator+"index.html"); //$NON-NLS-1$ |
| 1405 | link = extractLinkFrom(this.reportsRoot, refereehtml.getAbsolutePath()); |
| 1406 | buffer.append(getReferenceTableEntry(report.counts, link, report.name)); |
| 1407 | } |
| 1408 | } |
| 1409 | buffer.append(CLOSE_TABLE); |
| 1410 | } |
| 1411 | } |
| 1412 | else { |
| 1413 | buffer.append(getNoReportsInformation()); |
| 1414 | } |
| 1415 | buffer.append(W3C_FOOTER); |
| 1416 | buffer.append(CLOSE_BODY).append(CLOSE_HTML); |
| 1417 | |
| 1418 | //write the file |
| 1419 | FileWriter fileWriter = new FileWriter(htmlIndex); |
| 1420 | writer = new PrintWriter(new BufferedWriter(fileWriter)); |
| 1421 | writer.print(buffer.toString()); |
| 1422 | writer.flush(); |
| 1423 | } catch (IOException e) { |
| 1424 | throw new Exception(NLS.bind(SearchMessages.ioexception_writing_html_file, htmlIndex.getAbsolutePath())); |
| 1425 | } finally { |
| 1426 | if (writer != null) { |
| 1427 | writer.close(); |
| 1428 | } |
| 1429 | } |
| 1430 | } |
| 1431 | |
| 1432 | /** |
| 1433 | * @return the string to write if there are no reported bundles |
| 1434 | */ |
| 1435 | protected String getNoReportsInformation() { |
| 1436 | StringBuffer buffer = new StringBuffer(); |
| 1437 | buffer.append(OPEN_P).append(BR).append(SearchMessages.UseReportConverter_no_reported_usage).append(CLOSE_P); |
| 1438 | return buffer.toString(); |
| 1439 | } |
| 1440 | |
| 1441 | /** |
| 1442 | * This method is called during the HTML header creation phase to allow |
| 1443 | * META header elements to be written for metadata objects |
| 1444 | * @param buffer |
| 1445 | * @throws Exception |
| 1446 | */ |
| 1447 | void writeMetadataHeaders(StringBuffer buffer) throws Exception { |
| 1448 | writeMetaTag(buffer, "description", SearchMessages.UseReportConverter_root_index_description); //$NON-NLS-1$ |
| 1449 | //TODO could write metadata information here |
| 1450 | } |
| 1451 | |
| 1452 | /** |
| 1453 | * This method is called during the initial index page creation to allow |
| 1454 | * and executive summary of the use scan to be written out from metadata |
| 1455 | * @param buffer |
| 1456 | * @throws Exception |
| 1457 | */ |
| 1458 | void writeMetadataSummary(StringBuffer buffer) throws Exception { |
| 1459 | buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_scan_details).append(CLOSE_H4); |
| 1460 | getMetadata(); |
| 1461 | if(this.metadata != null) { |
| 1462 | buffer.append("<table border=\"0px\" title=\"").append(SearchMessages.UseReportConverter_scan_details).append("\"width=\"50%\">"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1463 | buffer.append(OPEN_TR); |
| 1464 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_scan_date).append(CLOSE_TD); |
| 1465 | buffer.append(openTD(36)).append(this.metadata.getRunAtDate()).append(CLOSE_TD); |
| 1466 | buffer.append(CLOSE_TR); |
| 1467 | buffer.append(OPEN_TR); |
| 1468 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_description).append(CLOSE_TD); |
| 1469 | String desc = this.metadata.getDescription(); |
| 1470 | buffer.append(openTD(36)).append((desc != null ? desc : SearchMessages.UseReportConverter_none)).append(CLOSE_TD); |
| 1471 | buffer.append(CLOSE_TR); |
| 1472 | buffer.append(OPEN_TR); |
| 1473 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_includes_API_refs).append(CLOSE_TD); |
| 1474 | buffer.append(openTD(36)).append(this.metadata.includesAPI()).append(CLOSE_TD); |
| 1475 | buffer.append(CLOSE_TR); |
| 1476 | buffer.append(OPEN_TR); |
| 1477 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_includes_internal_refs).append(CLOSE_TD); |
| 1478 | buffer.append(openTD(36)).append(this.metadata.includesInternal()).append(CLOSE_TD); |
| 1479 | buffer.append(CLOSE_TR); |
| 1480 | buffer.append(OPEN_TR); |
| 1481 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_baseline_loc).append(CLOSE_TD); |
| 1482 | buffer.append(openTD(36)).append(this.metadata.getBaselineLocation()).append(CLOSE_TD); |
| 1483 | buffer.append(CLOSE_TR); |
| 1484 | buffer.append(OPEN_TR); |
| 1485 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_scope_pattern).append(CLOSE_TD); |
| 1486 | buffer.append(openTD(36)).append(this.metadata.getScopePattern()).append(CLOSE_TD); |
| 1487 | buffer.append(CLOSE_TR); |
| 1488 | buffer.append(OPEN_TR); |
| 1489 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_reference_pattern).append(CLOSE_TD); |
| 1490 | buffer.append(openTD(36)).append(this.metadata.getReferencePattern()).append(CLOSE_TD); |
| 1491 | buffer.append(CLOSE_TR); |
| 1492 | buffer.append(OPEN_TR); |
| 1493 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_report_location).append(CLOSE_TD); |
| 1494 | buffer.append(openTD(36)).append(this.metadata.getReportLocation()).append(CLOSE_TD); |
| 1495 | buffer.append(CLOSE_TR); |
| 1496 | buffer.append(OPEN_TR); |
| 1497 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_api_pattern).append(CLOSE_TD); |
| 1498 | buffer.append(openTD(36)); |
| 1499 | String[] patterns = this.metadata.getApiPatterns(); |
| 1500 | if(patterns != null) { |
| 1501 | buffer.append(this.metadata.getApiPatterns()); |
| 1502 | for (int i = 0; i < patterns.length; i++) { |
| 1503 | buffer.append(patterns[i]).append(BR); |
| 1504 | } |
| 1505 | } |
| 1506 | else { |
| 1507 | buffer.append(SearchMessages.UseReportConverter_none); |
| 1508 | } |
| 1509 | buffer.append(CLOSE_TD); |
| 1510 | buffer.append(CLOSE_TR); |
| 1511 | buffer.append(OPEN_TR); |
| 1512 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_internal_patterns).append(CLOSE_TD); |
| 1513 | buffer.append(openTD(36)); |
| 1514 | patterns = this.metadata.getInternalPatterns(); |
| 1515 | if(patterns != null) { |
| 1516 | for (int i = 0; i < patterns.length; i++) { |
| 1517 | buffer.append(patterns[i]).append(BR); |
| 1518 | } |
| 1519 | } |
| 1520 | else { |
| 1521 | buffer.append(SearchMessages.UseReportConverter_none); |
| 1522 | } |
| 1523 | buffer.append(CLOSE_TD); |
| 1524 | buffer.append(CLOSE_TR); |
| 1525 | buffer.append(OPEN_TR); |
| 1526 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_archive_patterns).append(CLOSE_TD); |
| 1527 | buffer.append(openTD(36)); |
| 1528 | patterns = this.metadata.getArchivePatterns(); |
| 1529 | if(patterns != null) { |
| 1530 | for (int i = 0; i < patterns.length; i++) { |
| 1531 | buffer.append(patterns[i]).append(BR); |
| 1532 | } |
| 1533 | } |
| 1534 | else { |
| 1535 | buffer.append(SearchMessages.UseReportConverter_none); |
| 1536 | } |
| 1537 | buffer.append(CLOSE_TD); |
| 1538 | buffer.append(CLOSE_TR); |
| 1539 | buffer.append(OPEN_TR); |
| 1540 | buffer.append(openTD(14)).append(SearchMessages.UseReportConverter_filter_pattern).append(CLOSE_TD); |
| 1541 | buffer.append(openTD(36)); |
| 1542 | if(this.filterPatterns != null) { |
| 1543 | for (int i = 0; i < this.filterPatterns.length; i++) { |
| 1544 | buffer.append(this.filterPatterns[i].pattern()).append(BR); |
| 1545 | } |
| 1546 | } |
| 1547 | else { |
| 1548 | buffer.append(SearchMessages.UseReportConverter_none); |
| 1549 | } |
| 1550 | buffer.append(CLOSE_TD); |
| 1551 | buffer.append(CLOSE_TR); |
| 1552 | buffer.append(CLOSE_TABLE); |
| 1553 | } |
| 1554 | else { |
| 1555 | buffer.append(OPEN_P).append(SearchMessages.UseReportConverter_no_additional_scan_info).append(CLOSE_P); |
| 1556 | } |
| 1557 | } |
| 1558 | |
| 1559 | /** |
| 1560 | * Returns the use metadata from this scan |
| 1561 | * @return |
| 1562 | * @throws Exception |
| 1563 | */ |
| 1564 | UseMetadata getMetadata() throws Exception { |
| 1565 | if(this.metadata == null) { |
| 1566 | File xml = null; |
| 1567 | try { |
| 1568 | xml = new File(this.reportsRoot, "meta"+XML_EXTENSION); //$NON-NLS-1$ |
| 1569 | if(xml.exists()) { |
| 1570 | String xmlstr = Util.getFileContentAsString(xml); |
| 1571 | Element doc = Util.parseDocument(xmlstr); |
| 1572 | this.metadata = new UseMetadata(); |
| 1573 | Element element = null; |
| 1574 | String value = null, name = null; |
| 1575 | NodeList nodes = doc.getElementsByTagName("*"); //$NON-NLS-1$ |
| 1576 | for(int i = 0; i < nodes.getLength(); i++) { |
| 1577 | element = (Element) nodes.item(i); |
| 1578 | value = element.getAttribute(UseMetadata.VALUE); |
| 1579 | name = element.getNodeName(); |
| 1580 | if(UseMetadata.FLAGS.equals(name)) { |
| 1581 | try { |
| 1582 | this.metadata.setSearchflags(Integer.parseInt(value)); |
| 1583 | } |
| 1584 | catch(NumberFormatException nfe) { |
| 1585 | //do nothing |
| 1586 | } |
| 1587 | continue; |
| 1588 | } |
| 1589 | if(UseMetadata.RUNATDATE.equals(name)) { |
| 1590 | this.metadata.setRunAtDate(value); |
| 1591 | continue; |
| 1592 | } |
| 1593 | if(UseMetadata.DESCRIPTION.equals(name)) { |
| 1594 | this.metadata.setDescription(value); |
| 1595 | continue; |
| 1596 | } |
| 1597 | if(UseMetadata.BASELINELOCATION.equals(name)) { |
| 1598 | this.metadata.setBaselineLocation(value); |
| 1599 | continue; |
| 1600 | } |
| 1601 | if(UseMetadata.REPORTLOCATION.equals(name)) { |
| 1602 | this.metadata.setReportLocation(value); |
| 1603 | continue; |
| 1604 | } |
| 1605 | if(UseMetadata.SCOPEPATTERN.equals(name)) { |
| 1606 | this.metadata.setScopePattern(value); |
| 1607 | continue; |
| 1608 | } |
| 1609 | if(UseMetadata.REFERENCEPATTERN.equals(name)) { |
| 1610 | this.metadata.setReferencePattern(value); |
| 1611 | continue; |
| 1612 | } |
| 1613 | if(UseMetadata.APIPATTERNS.equals(name)) { |
| 1614 | this.metadata.setApiPatterns(readPatterns(element)); |
| 1615 | continue; |
| 1616 | } |
| 1617 | if(UseMetadata.INTERNALPATTERNS.equals(name)) { |
| 1618 | this.metadata.setInternalPatterns(readPatterns(element)); |
| 1619 | continue; |
| 1620 | } |
| 1621 | if(UseMetadata.ARCHIVEPATTERNS.equals(name)) { |
| 1622 | this.metadata.setArchivePatterns(readPatterns(element)); |
| 1623 | continue; |
| 1624 | } |
| 1625 | } |
| 1626 | } |
| 1627 | } |
| 1628 | catch (CoreException e) { |
| 1629 | throw new Exception(NLS.bind(SearchMessages.UseReportConverter_core_exep_reading_metadata, xml.getAbsolutePath())); |
| 1630 | } |
| 1631 | } |
| 1632 | return this.metadata; |
| 1633 | } |
| 1634 | |
| 1635 | /** |
| 1636 | * Reads saved patterns from the meta.xml file |
| 1637 | * @param element |
| 1638 | * @return the array of patterns or <code>null</code> |
| 1639 | */ |
| 1640 | private String[] readPatterns(Element element) { |
| 1641 | String[] pats = null; |
| 1642 | NodeList patterns = element.getElementsByTagName(UseMetadata.PATTERN); |
| 1643 | int length = patterns.getLength(); |
| 1644 | if(length > 0) { |
| 1645 | pats = new String[length]; |
| 1646 | for (int j = 0; j < length; j++) { |
| 1647 | pats[j] = ((Element)patterns.item(j)).getAttribute(UseMetadata.VALUE); |
| 1648 | } |
| 1649 | } |
| 1650 | return pats; |
| 1651 | } |
| 1652 | |
| 1653 | /** |
| 1654 | * Writes out a META tag of the kind <code>description</code> |
| 1655 | * @param buffer |
| 1656 | * @param description |
| 1657 | */ |
| 1658 | void writeMetaTag(StringBuffer buffer, String name, String content) { |
| 1659 | buffer.append("<meta name=\"").append(name).append("\" content=\"").append(content).append("\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 1660 | } |
| 1661 | |
| 1662 | /** |
| 1663 | * Returns the HTML markup for the default references table header. |
| 1664 | * Where the first column contains the linked item and the following five columns are |
| 1665 | * API, Internal, Permissible, Fragment-Permissible and Other reference counts respectively |
| 1666 | * @param columnname |
| 1667 | * @return the default references table header |
| 1668 | */ |
| 1669 | String getReferencesTableHeader(String columnname) { |
| 1670 | StringBuffer buffer = new StringBuffer(); |
| 1671 | buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_references).append(CLOSE_H4); |
| 1672 | buffer.append("<table border=\"1\" width=\"70%\">\n"); //$NON-NLS-1$ |
| 1673 | buffer.append(OPEN_TR); |
| 1674 | buffer.append("\t<td bgcolor=\"#CC9933\" width=\"30%\">").append(OPEN_B).append(columnname).append(CLOSE_B).append(CLOSE_TD); //$NON-NLS-1$ |
| 1675 | buffer.append("\t<td bgcolor=\"#CC9933\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ |
| 1676 | buffer.append(SearchMessages.UseReportConverter_api_ref_description).append("\"\">"); //$NON-NLS-1$ |
| 1677 | buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_api_references).append(CLOSE_B).append(CLOSE_TD); |
| 1678 | buffer.append("\t<td bgcolor=\"#CC9933\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ |
| 1679 | buffer.append(SearchMessages.UseReportConverter_internal_ref_description).append("\">"); //$NON-NLS-1$ |
| 1680 | buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_internal_references).append(CLOSE_B).append(CLOSE_TD); |
| 1681 | buffer.append("\t<td bgcolor=\"#CC9933\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ |
| 1682 | buffer.append(SearchMessages.UseReportConverter_permissible_ref_description).append("\">"); //$NON-NLS-1$ |
| 1683 | buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_internal_permissible_references).append(CLOSE_B).append(CLOSE_TD); |
| 1684 | buffer.append("\t<td bgcolor=\"#CC9933\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ |
| 1685 | buffer.append(SearchMessages.UseReportConverter_fragment_ref_description).append("\">"); //$NON-NLS-1$ |
| 1686 | buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_fragment_permissible_references).append(CLOSE_B).append(CLOSE_TD); |
| 1687 | buffer.append("\t<td bgcolor=\"#CC9933\" align=\"center\" width=\"8%\" title=\""); //$NON-NLS-1$ |
| 1688 | buffer.append(SearchMessages.UseReportConverter_other_ref_description).append("\">"); //$NON-NLS-1$ |
| 1689 | buffer.append(OPEN_B).append(SearchMessages.UseReportConverter_other_references).append(CLOSE_B).append(CLOSE_TD); |
| 1690 | buffer.append(CLOSE_TR); |
| 1691 | return buffer.toString(); |
| 1692 | } |
| 1693 | |
| 1694 | /** |
| 1695 | * Returns the HTML markup for one entry in the default references table. |
| 1696 | * Where the first column contains the linked item and the following five columns are |
| 1697 | * API, Internal, Permissible, Fragment-Permissible and Other reference counts respectively |
| 1698 | * @param counts |
| 1699 | * @param link |
| 1700 | * @param linktext |
| 1701 | * @return a single reference table entry |
| 1702 | */ |
| 1703 | String getReferenceTableEntry(CountGroup counts, String link, String linktext) { |
| 1704 | StringBuffer buffer = new StringBuffer(); |
| 1705 | buffer.append("<tr bgcolor=\"").append((counts.getTotalInternalRefCount() > 0 ? INTERNAL_REFS_COLOUR : NORMAL_REFS_COLOUR)).append("\">\n"); //$NON-NLS-1$//$NON-NLS-2$ |
| 1706 | buffer.append("\t<td><a href=\"").append(link).append("\">").append(linktext).append("</a>").append(CLOSE_TD); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 1707 | buffer.append("\t<td align=\"center\">").append(counts.getTotalApiRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1708 | buffer.append("\t<td align=\"center\">").append(counts.getTotalInternalRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1709 | buffer.append("\t<td align=\"center\">").append(counts.getTotalPermissableRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1710 | buffer.append("\t<td align=\"center\">").append(counts.getTotalFragmentPermissibleRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1711 | buffer.append("\t<td align=\"center\">").append(counts.getTotalOtherRefCount()).append(CLOSE_TD); //$NON-NLS-1$ |
| 1712 | buffer.append(CLOSE_TR); |
| 1713 | return buffer.toString(); |
| 1714 | } |
| 1715 | |
| 1716 | /** |
| 1717 | * Allows additional infos to be added to the HTML at the top of the report page |
| 1718 | * @param hasreports |
| 1719 | * |
| 1720 | * @return additional information string to add |
| 1721 | */ |
| 1722 | protected String getAdditionalIndexInfo(boolean hasreports) { |
| 1723 | return null; |
| 1724 | } |
| 1725 | |
| 1726 | /** |
| 1727 | * Returns HTML summary for references from a specific component. |
| 1728 | * |
| 1729 | * @param typename |
| 1730 | * @param counts |
| 1731 | * @return HTML as a string |
| 1732 | */ |
| 1733 | protected String getTypeCountSummary(String typename, CountGroup counts, int membercount) { |
| 1734 | StringBuffer buffer = new StringBuffer(); |
| 1735 | buffer.append(OPEN_H4).append(SearchMessages.UseReportConverter_summary).append(CLOSE_H4); |
| 1736 | 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); |
| 1737 | return buffer.toString(); |
| 1738 | } |
| 1739 | } |