70 import org.openjdk.jmc.flightrecorder.rules.Result;
71 import org.openjdk.jmc.flightrecorder.rules.Severity;
72 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.HtmlResultGroup;
73 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.HtmlResultProvider;
74 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.RulesHtmlToolkit;
75 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
76 import org.openjdk.jmc.flightrecorder.ui.DataPageDescriptor;
77 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
78 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
79 import org.openjdk.jmc.ui.misc.DisplayToolkit;
80
81 /**
82 * This class handles creation of a HTML/JS based result report, it has two modes, Single Page and
83 * Full Report. Single Page is used by the ResultPage PageBookView and the Full Report by the Result
84 * Overview page.
85 */
86 public class ResultReportUi {
87
88 private static final String OVERVIEW_MAKE_SCALABLE = "overview.makeScalable();"; //$NON-NLS-1$
89 private static final String OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY = "overview.updatePageHeadersVisibility();"; //$NON-NLS-1$
90 private static final Pattern HTML_ANCHOR_PATTERN = Pattern.compile("<a href=\"(.*?)\">(.*?)</a>");
91 private static final String OPEN_BROWSER_WINDOW = "openWindowByUrl";
92
93 private static class Linker extends BrowserFunction {
94
95 private Iterable<HtmlResultGroup> resultGroups;
96 private IPageContainer editor;
97
98 public Linker(Browser browser, String name, Iterable<HtmlResultGroup> resultGroups, IPageContainer editor) {
99 super(browser, name);
100 this.resultGroups = resultGroups;
101 this.editor = editor;
102 }
103
104 @Override
105 public Object function(Object[] arguments) {
106 if (arguments.length != 1 && !(arguments[0] instanceof String)) {
107 return null;
108 }
109 String id = arguments[0].toString();
110 for (HtmlResultGroup group : resultGroups) {
111 if (group instanceof PageDescriptorResultGroup && id.equals(group.getId())) {
274 });
275 }
276
277 /*
278 * We replace the anchors in the HTML when running in the JMC UI to make
279 * it possible to follow them. See JMC-5419 for more information.
280 */
281 private static String adjustAnchorFollowAction(String html) {
282 Map<String, String> map = new HashMap<>();
283 Matcher m = HTML_ANCHOR_PATTERN.matcher(html);
284 while (m.find()) {
285 map.put(m.group(1), m.group(2));
286 }
287 for(Map.Entry<String, String> e: map.entrySet()){
288 html = html.replace(e.getKey(), openWindowMethod(e.getKey(), e.getValue()));
289 }
290 return html;
291 }
292
293 private static String openWindowMethod(String url, String name){
294 return new StringBuilder().append("#\" onclick=\"").append(OPEN_BROWSER_WINDOW).append("(").append("\u0027")
295 .append(url).append("\u0027").append(',').append("\u0027")
296 .append(name).append("\u0027").append(");return false;").toString();
297 }
298
299 public ResultReportUi(boolean isSinglePage) {
300 this.isSinglePage = isSinglePage;
301 }
302
303 public List<String> getHtml(IPageContainer editor) {
304 List<String> overviewHtml = new ArrayList<>(1);
305 String adjustedHtml = adjustAnchorFollowAction(RulesHtmlToolkit.generateStructuredHtml(new PageContainerResultProvider(editor), descriptors,
306 resultExpandedStates, true));
307 overviewHtml.add(adjustedHtml);
308 return overviewHtml;
309 }
310
311 public void setShowOk(boolean showOk) {
312 this.showOk = showOk;
313 if (!isSinglePage) {
314 try {
315 // FIXME: Avoid implicit dependency on HTML/javascript template. Generate script in RulesHtmlToolkit instead
316 browser.evaluate(String.format("overview.showOk(%b);", showOk)); //$NON-NLS-1$
334 private Collection<String> topics = RulesToolkit.getAllTopics();
335 private Collection<Result> results;
336
337 public void updateRule(IRule rule) {
338 // FIXME: Possible race condition where elements may be added to the queue without being consumed
339 if (resultEventQueue.isEmpty()) {
340 resultEventQueue.add(rule);
341 DisplayToolkit.safeAsyncExec(() -> {
342 if (browser.isDisposed()) {
343 return;
344 }
345 // FIXME: Avoid implicit dependency on HTML/javascript template. Generate script in RulesHtmlToolkit instead
346 StringBuilder script = new StringBuilder();
347 while (!resultEventQueue.isEmpty()) {
348 IRule next = resultEventQueue.poll();
349 Result result = editor.getRuleManager().getResult(next);
350 if (result == null) {
351 continue;
352 }
353 long score = Math.round(result.getScore());
354 String adjustedHtml = adjustAnchorFollowAction(RulesHtmlToolkit.getDescription(result));//$NON-NLS-1$ //$NON-NLS-2$
355 String quoteEscape = adjustedHtml.replaceAll("\\\"", "\\\\\""); //$NON-NLS-1$ //$NON-NLS-2$
356 String description = quoteEscape.replaceAll("\n", "</br>"); //$NON-NLS-1$ //$NON-NLS-2$
357 script.append(String.format("overview.updateResult(\"%s\", %d, \"%s\");", //$NON-NLS-1$
358 result.getRule().getId(), score, description));
359 }
360 String[] topicsArray = topics.toArray(new String[topics.size()]);
361 if (!isSinglePage) {
362 boolean allOk = editor.getRuleManager().getScoreStream(topicsArray)
363 .allMatch(d -> d > RulesHtmlToolkit.IN_PROGRESS && d < Severity.INFO.getLimit()) && !showOk;
364 script.append(String.format("overview.allOk(%b);", allOk)); //$NON-NLS-1$
365 }
366 boolean allIgnored = editor.getRuleManager().getScoreStream(topicsArray)
367 .allMatch(d -> d == Result.IGNORE);
368 script.append(String.format("overview.allIgnored(%b);", allIgnored)); //$NON-NLS-1$
369 try {
370 if (isLoaded) {
371 browser.evaluate(script.toString());
372 browser.evaluate(OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY);
373 } else {
374 final String finalScript = script.toString();
413 try {
414 this.showOk = Boolean.valueOf(state.getChild("report").getChild("showOk").getAttribute("value")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
415 } catch (NullPointerException npe) {
416 }
417 browser.addListener(SWT.MenuDetect, new Listener() {
418 @Override
419 public void handleEvent(Event event) {
420 event.doit = false;
421 }
422 });
423 try {
424 String html = isSinglePage ? RulesHtmlToolkit.generateSinglePageHtml(results)
425 : RulesHtmlToolkit.generateStructuredHtml(new PageContainerResultProvider(editor), descriptors,
426 resultExpandedStates, false);
427 String adjustedHtml = adjustAnchorFollowAction(html);
428 browser.setText(adjustedHtml, true);
429 browser.setJavascriptEnabled(true);
430 browser.addProgressListener(new ProgressAdapter() {
431 @Override
432 public void completed(ProgressEvent event) {
433 new OpenWindowFunction(browser, OPEN_BROWSER_WINDOW); //$NON-NLS-1$
434 new Linker(browser, "linker", descriptors, editor); //$NON-NLS-1$
435 new Expander(browser, "expander"); //$NON-NLS-1$
436 browser.execute(String.format("overview.showOk(%b);", showOk)); //$NON-NLS-1$
437 if (isSinglePage) {
438 browser.execute(OVERVIEW_MAKE_SCALABLE);
439 }
440 browser.evaluate(OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY);
441 isLoaded = true;
442 }
443 });
444 } catch (IOException | IllegalArgumentException e) {
445 FlightRecorderUI.getDefault().getLogger().log(Level.WARNING, "Could not create Report Overview", e); //$NON-NLS-1$
446 return false;
447 }
448 return true;
449 }
450
451 public void saveTo(IWritableState state) {
452 state.createChild("report").createChild("showOk").putString("value", showOk.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
453 }
|
70 import org.openjdk.jmc.flightrecorder.rules.Result;
71 import org.openjdk.jmc.flightrecorder.rules.Severity;
72 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.HtmlResultGroup;
73 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.HtmlResultProvider;
74 import org.openjdk.jmc.flightrecorder.rules.report.html.internal.RulesHtmlToolkit;
75 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
76 import org.openjdk.jmc.flightrecorder.ui.DataPageDescriptor;
77 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
78 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
79 import org.openjdk.jmc.ui.misc.DisplayToolkit;
80
81 /**
82 * This class handles creation of a HTML/JS based result report, it has two modes, Single Page and
83 * Full Report. Single Page is used by the ResultPage PageBookView and the Full Report by the Result
84 * Overview page.
85 */
86 public class ResultReportUi {
87
88 private static final String OVERVIEW_MAKE_SCALABLE = "overview.makeScalable();"; //$NON-NLS-1$
89 private static final String OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY = "overview.updatePageHeadersVisibility();"; //$NON-NLS-1$
90 private static final Pattern HTML_ANCHOR_PATTERN = Pattern.compile("<a href=\"(.*?)\">(.*?)</a>"); //$NON-NLS-1$
91 private static final String OPEN_BROWSER_WINDOW = "openWindowByUrl"; //$NON-NLS-1$
92
93 private static class Linker extends BrowserFunction {
94
95 private Iterable<HtmlResultGroup> resultGroups;
96 private IPageContainer editor;
97
98 public Linker(Browser browser, String name, Iterable<HtmlResultGroup> resultGroups, IPageContainer editor) {
99 super(browser, name);
100 this.resultGroups = resultGroups;
101 this.editor = editor;
102 }
103
104 @Override
105 public Object function(Object[] arguments) {
106 if (arguments.length != 1 && !(arguments[0] instanceof String)) {
107 return null;
108 }
109 String id = arguments[0].toString();
110 for (HtmlResultGroup group : resultGroups) {
111 if (group instanceof PageDescriptorResultGroup && id.equals(group.getId())) {
274 });
275 }
276
277 /*
278 * We replace the anchors in the HTML when running in the JMC UI to make
279 * it possible to follow them. See JMC-5419 for more information.
280 */
281 private static String adjustAnchorFollowAction(String html) {
282 Map<String, String> map = new HashMap<>();
283 Matcher m = HTML_ANCHOR_PATTERN.matcher(html);
284 while (m.find()) {
285 map.put(m.group(1), m.group(2));
286 }
287 for(Map.Entry<String, String> e: map.entrySet()){
288 html = html.replace(e.getKey(), openWindowMethod(e.getKey(), e.getValue()));
289 }
290 return html;
291 }
292
293 private static String openWindowMethod(String url, String name){
294 return new StringBuilder().append("#\" onclick=\"").append(OPEN_BROWSER_WINDOW).append("(").append("\u0027") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
295 .append(url).append("\u0027").append(',').append("\u0027") //$NON-NLS-1$ //$NON-NLS-2$
296 .append(name).append("\u0027").append(");return false;").toString(); //$NON-NLS-1$//$NON-NLS-2$
297 }
298
299 public ResultReportUi(boolean isSinglePage) {
300 this.isSinglePage = isSinglePage;
301 }
302
303 public List<String> getHtml(IPageContainer editor) {
304 List<String> overviewHtml = new ArrayList<>(1);
305 String adjustedHtml = adjustAnchorFollowAction(RulesHtmlToolkit.generateStructuredHtml(new PageContainerResultProvider(editor), descriptors,
306 resultExpandedStates, true));
307 overviewHtml.add(adjustedHtml);
308 return overviewHtml;
309 }
310
311 public void setShowOk(boolean showOk) {
312 this.showOk = showOk;
313 if (!isSinglePage) {
314 try {
315 // FIXME: Avoid implicit dependency on HTML/javascript template. Generate script in RulesHtmlToolkit instead
316 browser.evaluate(String.format("overview.showOk(%b);", showOk)); //$NON-NLS-1$
334 private Collection<String> topics = RulesToolkit.getAllTopics();
335 private Collection<Result> results;
336
337 public void updateRule(IRule rule) {
338 // FIXME: Possible race condition where elements may be added to the queue without being consumed
339 if (resultEventQueue.isEmpty()) {
340 resultEventQueue.add(rule);
341 DisplayToolkit.safeAsyncExec(() -> {
342 if (browser.isDisposed()) {
343 return;
344 }
345 // FIXME: Avoid implicit dependency on HTML/javascript template. Generate script in RulesHtmlToolkit instead
346 StringBuilder script = new StringBuilder();
347 while (!resultEventQueue.isEmpty()) {
348 IRule next = resultEventQueue.poll();
349 Result result = editor.getRuleManager().getResult(next);
350 if (result == null) {
351 continue;
352 }
353 long score = Math.round(result.getScore());
354 String adjustedHtml = adjustAnchorFollowAction(RulesHtmlToolkit.getDescription(result));
355 String quoteEscape = adjustedHtml.replaceAll("\\\"", "\\\\\""); //$NON-NLS-1$ //$NON-NLS-2$
356 String description = quoteEscape.replaceAll("\n", "</br>"); //$NON-NLS-1$ //$NON-NLS-2$
357 script.append(String.format("overview.updateResult(\"%s\", %d, \"%s\");", //$NON-NLS-1$
358 result.getRule().getId(), score, description));
359 }
360 String[] topicsArray = topics.toArray(new String[topics.size()]);
361 if (!isSinglePage) {
362 boolean allOk = editor.getRuleManager().getScoreStream(topicsArray)
363 .allMatch(d -> d > RulesHtmlToolkit.IN_PROGRESS && d < Severity.INFO.getLimit()) && !showOk;
364 script.append(String.format("overview.allOk(%b);", allOk)); //$NON-NLS-1$
365 }
366 boolean allIgnored = editor.getRuleManager().getScoreStream(topicsArray)
367 .allMatch(d -> d == Result.IGNORE);
368 script.append(String.format("overview.allIgnored(%b);", allIgnored)); //$NON-NLS-1$
369 try {
370 if (isLoaded) {
371 browser.evaluate(script.toString());
372 browser.evaluate(OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY);
373 } else {
374 final String finalScript = script.toString();
413 try {
414 this.showOk = Boolean.valueOf(state.getChild("report").getChild("showOk").getAttribute("value")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
415 } catch (NullPointerException npe) {
416 }
417 browser.addListener(SWT.MenuDetect, new Listener() {
418 @Override
419 public void handleEvent(Event event) {
420 event.doit = false;
421 }
422 });
423 try {
424 String html = isSinglePage ? RulesHtmlToolkit.generateSinglePageHtml(results)
425 : RulesHtmlToolkit.generateStructuredHtml(new PageContainerResultProvider(editor), descriptors,
426 resultExpandedStates, false);
427 String adjustedHtml = adjustAnchorFollowAction(html);
428 browser.setText(adjustedHtml, true);
429 browser.setJavascriptEnabled(true);
430 browser.addProgressListener(new ProgressAdapter() {
431 @Override
432 public void completed(ProgressEvent event) {
433 new OpenWindowFunction(browser, OPEN_BROWSER_WINDOW);
434 new Linker(browser, "linker", descriptors, editor); //$NON-NLS-1$
435 new Expander(browser, "expander"); //$NON-NLS-1$
436 browser.execute(String.format("overview.showOk(%b);", showOk)); //$NON-NLS-1$
437 if (isSinglePage) {
438 browser.execute(OVERVIEW_MAKE_SCALABLE);
439 }
440 browser.evaluate(OVERVIEW_UPDATE_PAGE_HEADERS_VISIBILITY);
441 isLoaded = true;
442 }
443 });
444 } catch (IOException | IllegalArgumentException e) {
445 FlightRecorderUI.getDefault().getLogger().log(Level.WARNING, "Could not create Report Overview", e); //$NON-NLS-1$
446 return false;
447 }
448 return true;
449 }
450
451 public void saveTo(IWritableState state) {
452 state.createChild("report").createChild("showOk").putString("value", showOk.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
453 }
|