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 | } |