package org.yamcs.ui; import java.awt.Component; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; import org.yamcs.api.YamcsConnectionProperties; import org.yamcs.api.rest.RestClient; import org.yamcs.protobuf.Commanding.CommandHistoryEntry; import org.yamcs.utils.CommandHistoryFormatter; import org.yamcs.utils.TimeEncoding; /** * @author nm * GUI for requesting packet dumps */ public class CommandHistoryRetrievalGui extends JFrame implements ActionListener { JButton startStop; JFileChooser fileChooser; List<String> cmdNames; long startInstant, stopInstant; String archiveInstance; Component parent; ProgressMonitor progressMonitor; private File outputFile; private BufferedWriter writer; YamcsConnectionProperties connectionParams; CommandHistoryFormatter cmdhistFormatter; private CompletableFuture<Void> completableFuture; /** * Creates a new window that requests parameter deliveries * @param parent * */ public CommandHistoryRetrievalGui(YamcsConnectionProperties connectionParams, Component parent) { super("Save Command History"); this.connectionParams=connectionParams; this.parent=parent; Container frameContentPane=getContentPane(); frameContentPane.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); JLabel label=new JLabel("Saving the command history for the selected interval into a file."); gbc.gridx=0;gbc.gridy=0;gbc.gridwidth=GridBagConstraints.REMAINDER; //gbc.ipadx=5; gbc.ipady=5; gbc.insets=new Insets(5,5,5,5); frameContentPane.add(label,gbc); //options gbc.insets=new Insets(2,2,2,2); fileChooser=new JFileChooser("Select Output Directory"); fileChooser.setApproveButtonText("Save"); fileChooser.addActionListener(this); gbc.gridy=2;gbc.gridx=0;gbc.gridwidth=GridBagConstraints.REMAINDER;gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1.0;gbc.weightx = 1.0; frameContentPane.add(fileChooser,gbc); pack(); } public void setValues(String archiveInstance, List<String> cmdNames, long start, long stop) { this.cmdNames=cmdNames; this.startInstant=start; this.stopInstant=stop; this.archiveInstance=archiveInstance; String startWinCompatibleDateTime = TimeEncoding.toWinCompatibleDateTime(startInstant); String stopWinCompatibleDateTime = TimeEncoding.toWinCompatibleDateTime(stopInstant); String fileName = String.format("cmdhistory_%s_%s.csv" ,startWinCompatibleDateTime ,stopWinCompatibleDateTime); fileChooser.setSelectedFile(new File(fileChooser.getSelectedFile(), fileName)); } @Override public void actionPerformed(ActionEvent ae) { String cmd = ae.getActionCommand(); if(cmd.equals("CancelSelection")) { setVisible(false); } else { outputFile=fileChooser.getSelectedFile(); if(outputFile.exists()) { if(JOptionPane.showConfirmDialog(this, "Are you sure you want to overwrite "+outputFile,"Overwrite file?",JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE) ==JOptionPane.NO_OPTION) { return; } } setVisible(false); count = 0; downloadStartTime=System.currentTimeMillis(); progressMonitor = new ProgressMonitor(parent,"Saving packets","0 packets saved",0,(int)((stopInstant-startInstant)/1000)); try { writer=new BufferedWriter(new FileWriter(outputFile)); cmdhistFormatter=new CommandHistoryFormatter(writer); RestClient restClient = new RestClient(connectionParams); StringBuilder sb = new StringBuilder(); sb.append("/archive/").append(archiveInstance).append("/downloads/commands") .append("?start=").append(TimeEncoding.toString(startInstant)) .append("&stop=").append(TimeEncoding.toString(stopInstant)) .append("&name="); completableFuture = restClient.doBulkGetRequest(sb.toString(), (data) -> { try { CommandHistoryEntry che = CommandHistoryEntry.parseFrom(data); receivedCommadHistory(che); } catch (Exception e) { e.printStackTrace(); } }); completableFuture.whenComplete((v, t) ->{ if((t==null) || (t instanceof CancellationException)) { replayFinished(); } else { exception(t); } }); } catch (FileNotFoundException e1) { JOptionPane.showMessageDialog(parent, "Cannot open file: "+e1.getMessage(),"Cannot open file",JOptionPane.ERROR_MESSAGE); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(parent, "Exception when retrieving data: "+e,"Exception when retrieving data",JOptionPane.ERROR_MESSAGE); } } } int count; long downloadStartTime; private void receivedCommadHistory(CommandHistoryEntry che) throws IOException { int progr=(int)((che.getCommandId().getGenerationTime() - startInstant)/1000); count++; if(count%100==0) progressMonitor.setNote(count+" packets received"); progressMonitor.setProgress(progr); cmdhistFormatter.writeCommand(che); } private void replayFinished() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { try { cmdhistFormatter.close(); } catch (IOException e) { JOptionPane.showMessageDialog(parent, "Error when closing the output file: "+e.getMessage(), "Error when closing the output file", JOptionPane.ERROR_MESSAGE); } if(progressMonitor.isCanceled()) { JOptionPane.showMessageDialog(parent, "Retrieval canceled. "+count+" packets retrieved"); } else { progressMonitor.close(); float speed=(count*1000)/(System.currentTimeMillis()-downloadStartTime); JOptionPane.showMessageDialog(parent, "The command retrieval finished successfully. "+count+" commands retrieved in "+outputFile+". Retrieval speed: "+speed+" cmd/sec"); } } }); } public void exception(final Throwable e) { final String message; message=e.toString(); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(parent, message, message, JOptionPane.ERROR_MESSAGE); progressMonitor.close(); } }); } }