/*
* JBoss, Home of Professional Open Source
* Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.jboss.as.cli.gui.metacommand;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.Dialog;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ProgressMonitor;
import javax.swing.SwingWorker;
import org.jboss.as.cli.CommandFormatException;
import org.jboss.as.cli.gui.CliGuiContext;
import org.jboss.as.cli.gui.CommandExecutor.Response;
import org.jboss.as.controller.client.OperationResponse.StreamEntry;
import org.jboss.as.controller.client.helpers.Operations;
import org.jboss.dmr.ModelNode;
/**
* Dialog to choose destination file and download log.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public class DownloadServerLogDialog extends JDialog implements ActionListener, PropertyChangeListener {
// make these static so that they always retains the last value chosen
private static final JFileChooser fileChooser = new JFileChooser(new File("."));
private static final JCheckBox viewInLogViewer = new JCheckBox("View in default log viewer");
static {
viewInLogViewer.setSelected(true);
}
private CliGuiContext cliGuiCtx;
private String fileName;
private Long fileSize;
private JPanel inputPanel = new JPanel(new GridBagLayout());
private JTextField pathField = new JTextField(40);
private ProgressMonitor progressMonitor;
private DownloadLogTask downloadTask;
private boolean openInViewerSupported = Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN);
public DownloadServerLogDialog(CliGuiContext cliGuiCtx, String fileName, Long fileSize) {
super(cliGuiCtx.getMainWindow(), "Download " + fileName, Dialog.ModalityType.APPLICATION_MODAL);
this.cliGuiCtx = cliGuiCtx;
this.fileName = fileName;
this.fileSize = fileSize;
fileChooser.setSelectedFile(new File(fileChooser.getCurrentDirectory(), fileName));
setPathField();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout(10, 10));
contentPane.add(makeInputPanel(), BorderLayout.CENTER);
contentPane.add(makeButtonPanel(), BorderLayout.SOUTH);
pack();
setResizable(false);
}
private void setPathField() {
try {
pathField.setText(fileChooser.getSelectedFile().getCanonicalPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private JPanel makeInputPanel() {
GridBagConstraints gbConst = new GridBagConstraints();
gbConst.anchor = GridBagConstraints.WEST;
gbConst.insets = new Insets(5, 5, 5, 5);
JLabel pathLabel = new JLabel("Download To:");
gbConst.gridwidth = 1;
inputPanel.add(pathLabel, gbConst);
addStrut();
inputPanel.add(pathField, gbConst);
addStrut();
JButton browse = new JButton("Browse ...");
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
int returnVal = fileChooser.showOpenDialog(DownloadServerLogDialog.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
setPathField();
}
}
});
gbConst.gridwidth = GridBagConstraints.REMAINDER;
inputPanel.add(browse, gbConst);
if (openInViewerSupported) {
JLabel emptyLabel = new JLabel("");
gbConst.gridwidth = 1;
inputPanel.add(emptyLabel, gbConst);
addStrut();
gbConst.gridwidth = GridBagConstraints.REMAINDER;
inputPanel.add(viewInLogViewer, gbConst);
}
return inputPanel;
}
private void addStrut() {
inputPanel.add(Box.createHorizontalStrut(5));
}
private JPanel makeButtonPanel() {
JPanel buttonPanel = new JPanel();
JButton ok = new JButton("OK");
ok.addActionListener(this);
ok.setMnemonic(KeyEvent.VK_ENTER);
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
DownloadServerLogDialog.this.dispose();
}
});
buttonPanel.add(ok);
buttonPanel.add(cancel);
return buttonPanel;
}
@Override
public void actionPerformed(ActionEvent event) {
String path = pathField.getText();
if (path.trim().isEmpty()) {
JOptionPane.showMessageDialog(this, "A file path must be selected.", "Empty File Path", JOptionPane.ERROR_MESSAGE);
return;
}
File selectedFile = new File(path);
if (selectedFile.exists()) {
this.setVisible(false);
int option = JOptionPane.showConfirmDialog(cliGuiCtx.getMainWindow(), "Overwrite " + path, "Overwrite?", JOptionPane.YES_NO_OPTION);
if (option == JOptionPane.NO_OPTION) {
this.setVisible(true);
return;
}
}
this.dispose();
progressMonitor = new ProgressMonitor(cliGuiCtx.getMainWindow(), "Downloading " + fileName, "", 0, 100);
progressMonitor.setProgress(0);
downloadTask = new DownloadLogTask(selectedFile);
downloadTask.addPropertyChangeListener(this);
downloadTask.execute();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())){
int percentRead = (Integer) evt.getNewValue();
progressMonitor.setProgress(percentRead);
}
if ("bytesRead".equals(evt.getPropertyName())) {
progressMonitor.setNote(evt.getNewValue() + " of " + fileSize + " bytes received.");
}
if (progressMonitor.isCanceled()) {
downloadTask.cancel(false);
}
}
class DownloadLogTask extends SwingWorker<Void, Void> {
private final File selectedFile;
public DownloadLogTask(File selectedFile) {
this.selectedFile = selectedFile;
}
@Override
public Void doInBackground() {
try {
String command = "/subsystem=logging/log-file=" + fileName + ":read-attribute(name=stream)";
final Response response = cliGuiCtx.getExecutor().doCommandFullResponse(command);
final ModelNode outcome = response.getDmrResponse();
if (!Operations.isSuccessfulOutcome(outcome)) {
cancel(false);
String error = "Failure at server: " + Operations.getFailureDescription(outcome).asString();
JOptionPane.showMessageDialog(cliGuiCtx.getMainWindow(), error, "Download Failed", JOptionPane.ERROR_MESSAGE);
return null;
}
// Get the UUID of the stream
final String uuid = Operations.readResult(outcome).asString();
// Should only be a single entry
final byte[] buffer = new byte[512];
try (
final StreamEntry entry = response.getOperationResponse().getInputStream(uuid);
final InputStream in = entry.getStream();
final OutputStream out = Files.newOutputStream(selectedFile.toPath(), StandardOpenOption.CREATE);
) {
int bytesRead = 0;
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
final int oldValue = bytesRead;
bytesRead += len;
firePropertyChange("bytesRead", oldValue, bytesRead);
setProgress(Math.max(Math.round(((float) bytesRead / (float) fileSize) * 100), 100));
}
}
} catch (IOException | CommandFormatException ex) {
throw new RuntimeException(ex);
} finally {
if (isCancelled()) {
selectedFile.delete();
}
}
return null;
}
@Override
public void done() {
String message = "Download " + fileName + " ";
if (isCancelled()) {
JOptionPane.showMessageDialog(cliGuiCtx.getMainWindow(), message + "cancelled.", message + "cancelled.", JOptionPane.ERROR_MESSAGE);
return;
}
if (!viewInLogViewer.isSelected() || !openInViewerSupported) {
JOptionPane.showMessageDialog(cliGuiCtx.getMainWindow(), message + "complete.");
return;
}
try {
Desktop.getDesktop().open(selectedFile);
} catch (IOException ioe) {
// try to open in file manager for destination directory
try {
Desktop.getDesktop().open(fileChooser.getCurrentDirectory());
} catch (IOException ioe2) {
JOptionPane.showMessageDialog(cliGuiCtx.getMainWindow(), "Download success. No registered application to view " + fileName, "Can't view file.", JOptionPane.ERROR_MESSAGE);
}
}
}
}
}