Skip to content

Commit

Permalink
8330584: IGV: XML does not save all node properties
Browse files Browse the repository at this point in the history
Reviewed-by: rcastanedalo, chagedorn
  • Loading branch information
tobiasholenstein committed May 13, 2024
1 parent adaa509 commit 391bbbc
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,17 @@
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;
Expand All @@ -66,6 +67,9 @@
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;


/**
*
Expand All @@ -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<FolderNode> selectedFolders = new HashSet<>();
Expand Down Expand Up @@ -161,8 +155,26 @@ private static void saveGraphDocument(GraphDocument doc, String path) throws IOE
}
}

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

Expand Down Expand Up @@ -358,7 +370,7 @@ public void clearWorkspace() {
**/
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();
Expand Down Expand Up @@ -403,9 +415,22 @@ public void save() {
}

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();
Expand All @@ -432,7 +457,7 @@ public void saveAs() {
**/
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) {
Expand Down Expand Up @@ -482,60 +507,83 @@ private static void loadContext(GraphContext context) {
}

/**
* 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<GraphContext> 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<GraphContext> 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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -23,6 +23,8 @@
*/
package com.sun.hotspot.igv.data;

import java.util.Objects;

/**
*
* @author Thomas Wuerthinger
Expand All @@ -49,17 +51,21 @@ public int getId() {
}

@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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,15 @@ private static void exportInputGraph(XMLWriter writer, InputGraph graph, InputGr
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
Expand Down Expand Up @@ -227,6 +232,10 @@ private static void exportInputMethod(XMLWriter w, InputMethod method) throws IO
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");
}

Expand Down

0 comments on commit 391bbbc

Please sign in to comment.