From 391bbbc7d0fb95b0cd55e2f56c43bee019aeab7f Mon Sep 17 00:00:00 2001 From: Tobias Holenstein Date: Mon, 13 May 2024 09:14:17 +0000 Subject: [PATCH] 8330584: IGV: XML does not save all node properties Reviewed-by: rcastanedalo, chagedorn --- .../igv/coordinator/OutlineTopComponent.java | 164 +++++++++++------- .../com/sun/hotspot/igv/data/InputNode.java | 18 +- .../igv/data/serialization/Printer.java | 17 +- 3 files changed, 131 insertions(+), 68 deletions(-) diff --git a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java index c66c40810c0..9508a5dfbca 100644 --- a/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java +++ b/src/utils/IdealGraphVisualizer/Coordinator/src/main/java/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java @@ -41,16 +41,17 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.io.*; import java.nio.channels.FileChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipInputStream; import javax.swing.*; import javax.swing.border.Border; import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.ErrorManager; @@ -66,6 +67,9 @@ import org.openide.util.NbBundle; import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; + /** * @@ -76,17 +80,7 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM public static final String PREFERRED_ID = "OutlineTopComponent"; private static final GraphDocument document = new GraphDocument(); private static final int WORK_UNITS = 10000; - private static final FileFilter xmlFileFilter = new FileFilter() { - @Override - public boolean accept(File f) { - return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory(); - } - - @Override - public String getDescription() { - return "Graph files (*.xml)"; - } - }; + private static final FileFilter graphFileFilter = new FileNameExtensionFilter("Graph files (*.xml, *.igv)", "xml", "igv"); private static final Server server = new Server(document, OutlineTopComponent::loadContext); public static OutlineTopComponent instance; private final Set selectedFolders = new HashSet<>(); @@ -161,8 +155,26 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM } } - try (Writer writer = new OutputStreamWriter(new FileOutputStream(path))) { - Printer.exportGraphDocument(writer, doc, saveContexts); + if (path.endsWith(".igv")) { + File zipFile = new File(path); + String fileName = zipFile.getName(); + try (FileOutputStream fos = new FileOutputStream(zipFile); + ZipOutputStream zos = new ZipOutputStream(fos); + Writer writer = new OutputStreamWriter(zos)) { + + // Replace the '.igv' extension with '.xml's + String zipEntryName = fileName.substring(0, fileName.length() - 4) + ".xml"; + ZipEntry zipEntry = new ZipEntry(zipEntryName); + zos.putNextEntry(zipEntry); + + Printer.exportGraphDocument(writer, doc, saveContexts); + + zos.closeEntry(); + } + } else { + try (Writer writer = new OutputStreamWriter(new FileOutputStream(path))) { + Printer.exportGraphDocument(writer, doc, saveContexts); + } } } @@ -358,7 +370,7 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM **/ public void openFile() { JFileChooser fc = new JFileChooser(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT)); - fc.setFileFilter(xmlFileFilter); + fc.setFileFilter(graphFileFilter); if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { clearWorkspace(); String path = fc.getSelectedFile().getAbsolutePath(); @@ -403,9 +415,22 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM } public void saveAs() { - JFileChooser fc = new JFileChooser(); + JFileChooser fc = new JFileChooser() { + @Override + public void approveSelection() { + File selectedFile = getSelectedFile(); + if (selectedFile != null) { + String fileName = selectedFile.getName().toLowerCase(); + if (!fileName.endsWith(".xml") && !fileName.endsWith(".igv")) { + JOptionPane.showMessageDialog(this, "Please select a graph file with .xml or .igv extension.", "Invalid File", JOptionPane.ERROR_MESSAGE); + return; + } + } + super.approveSelection(); + } + }; fc.setDialogTitle("Save As..."); - fc.setFileFilter(xmlFileFilter); + fc.setFileFilter(graphFileFilter); fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT))); if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { String path = fc.getSelectedFile().getAbsolutePath(); @@ -432,7 +457,7 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM **/ public void importFromXML() { JFileChooser fc = new JFileChooser(); - fc.setFileFilter(xmlFileFilter); + fc.setFileFilter(graphFileFilter); fc.setCurrentDirectory(new File(Settings.get().get(Settings.DIRECTORY, Settings.DIRECTORY_DEFAULT))); fc.setMultiSelectionEnabled(true); if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { @@ -482,60 +507,83 @@ public final class OutlineTopComponent extends TopComponent implements ExplorerM } /** - * Loads a graph document from the given file path, updating progress via a ProgressHandle. - * Parse the XML file, add the parsed document to the workspace, and load associated contexts if specified. + * Loads a graph document from the specified path, either as an XML file or from a ZIP archive. + * If loading the context is requested, it loads the context along with the document. */ private void loadGraphDocument(String path, boolean loadContext) throws IOException { if (Files.notExists(Path.of(path))) { return; } File file = new File(path); - final FileChannel channel; - final long start; - try { - channel = FileChannel.open(file.toPath(), StandardOpenOption.READ); - start = channel.size(); - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - return; + if (file.getName().endsWith(".xml")) { + try (FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.READ)) { + loadFile(channel, file, loadContext); + } + } else if (file.getName().endsWith(".igv")) { + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(file))) { + ZipEntry entry = zis.getNextEntry(); + if (entry != null && entry.getName().endsWith(".xml")) { + loadFile(Channels.newChannel(zis), file, loadContext); + } + } } + } + /** + * Loads an XML or ZIP document from the provided channel, while monitoring the progress of the operation. + */ + private void loadFile(ReadableByteChannel channel, File file, boolean loadContext) throws IOException { final ProgressHandle handle = ProgressHandleFactory.createHandle("Opening file " + file.getName()); handle.start(WORK_UNITS); - ParseMonitor monitor = new ParseMonitor() { - @Override - public void updateProgress() { - try { - int prog = (int) (WORK_UNITS * (double) channel.position() / (double) start); - handle.progress(prog); - } catch (IOException ignored) { + ParseMonitor monitor; + if (channel instanceof FileChannel fileChannel) { + final long start = fileChannel.size(); + monitor = new ParseMonitor() { + @Override + public void updateProgress() { + try { + int prog = (int) (WORK_UNITS * (double) fileChannel.position() / (double) start); + handle.progress(prog); + } catch (IOException ignored) {} } - } - @Override - public void setState(String state) { - updateProgress(); - handle.progress(state); - } - }; + @Override + public void setState(String state) { + updateProgress(); + handle.progress(state); + } + }; + } else { + monitor = new ParseMonitor() { + @Override + public void updateProgress() { + handle.progress("Processing..."); + } + + @Override + public void setState(String state) { + updateProgress(); + handle.progress(state); + } + }; + } + try { - if (file.getName().endsWith(".xml")) { - ArrayList contexts = new ArrayList<>(); - final Parser parser = new Parser(channel, monitor, document, loadContext ? contexts::add : null); - parser.parse(); - SwingUtilities.invokeLater(() -> { - for (Node child : manager.getRootContext().getChildren().getNodes(true)) { - // Nodes are lazily created. By expanding and collapsing they are all initialized - ((BeanTreeView) this.treeView).expandNode(child); - ((BeanTreeView) this.treeView).collapseNode(child); - } - requestActive(); - }); + ArrayList contexts = new ArrayList<>(); + final Parser parser = new Parser(channel, monitor, document, loadContext ? contexts::add : null); + parser.parse(); + SwingUtilities.invokeLater(() -> { + for (Node child : manager.getRootContext().getChildren().getNodes(true)) { + // Nodes are lazily created. By expanding and collapsing they are all initialized + ((BeanTreeView) this.treeView).expandNode(child); + ((BeanTreeView) this.treeView).collapseNode(child); + } + requestActive(); for (GraphContext ctx : contexts) { loadContext(ctx); } - } + }); } catch (IOException ex) { Exceptions.printStackTrace(ex); } diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java index 75b8b17ed5a..f2e1ad16ea6 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ */ package com.sun.hotspot.igv.data; +import java.util.Objects; + /** * * @author Thomas Wuerthinger @@ -49,17 +51,21 @@ public class InputNode extends Properties.Entity { } @Override - public boolean equals(Object o) { - if (!(o instanceof InputNode)) { + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { return false; } - InputNode n = (InputNode) o; - return n.id == id; + InputNode other = (InputNode) obj; + return id == other.id && + Objects.equals(getProperties(), other.getProperties()); } @Override public int hashCode() { - return id * 13; + return Objects.hash(id, getProperties()); } @Override diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java index f930e478776..b098b6ef5da 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Printer.java @@ -103,10 +103,15 @@ public class Printer { for (InputNode n : removed) { writer.simpleTag(Parser.REMOVE_NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId()))); } - } - - for (InputNode n : graph.getNodes()) { - if (!difference || !equal.contains(n)) { + for (InputNode n : graph.getNodes()) { + if (!equal.contains(n)) { + writer.startTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId()))); + writer.writeProperties(n.getProperties()); + writer.endTag(); // Parser.NODE_ELEMENT + } + } + } else { + for (InputNode n : graph.getNodes()) { writer.startTag(Parser.NODE_ELEMENT, new Properties(Parser.NODE_ID_PROPERTY, Integer.toString(n.getId()))); writer.writeProperties(n.getProperties()); writer.endTag(); // Parser.NODE_ELEMENT @@ -227,6 +232,10 @@ public class Printer { b.append(code.getBci()); b.append(" "); b.append(code.getName()); + b.append(" "); + b.append(code.getOperands()); + b.append(" "); + b.append(code.getComment()); b.append("\n"); }