com.haskins.cloudtrailviewer.dialog.S3FileChooser.java Source code

Java tutorial

Introduction

Here is the source code for com.haskins.cloudtrailviewer.dialog.S3FileChooser.java

Source

/*    
CloudTrail Viewer, is a Java desktop application for reading AWS CloudTrail logs
files.
    
Copyright (C) 2015  Mark P. Haskins
    
This program is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE.  See the GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.haskins.cloudtrailviewer.dialog;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.haskins.cloudtrailviewer.core.DbManager;
import com.haskins.cloudtrailviewer.model.AwsAccount;
import com.haskins.cloudtrailviewer.utils.ResultSetRow;
import com.haskins.cloudtrailviewer.utils.ToolBarUtils;
import java.awt.BorderLayout;
import java.awt.Component;
import static java.awt.Component.LEFT_ALIGNMENT;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;

/**
 * Shows a File Choose style dialog that loads files from an S3 bucket.
 * @author mark
 */
public class S3FileChooser extends JDialog implements ActionListener {

    private static final String MOVE_BACK = "..";

    private static S3FileChooser dialog;
    private static final List<String> selectedKeys = new ArrayList<>();

    private final DefaultListModel<S3ListModel> s3ListModel = new DefaultListModel();
    private final JList s3List;

    private static final DefaultComboBoxModel accountList = new DefaultComboBoxModel();
    private static final Map<String, AwsAccount> accountMap = new HashMap<>();
    private static AwsAccount currentAccount = null;

    private static final Map<String, String> aliasMap = new HashMap<>();
    private static String prefix = "";

    private JLabel loadingLabel = new JLabel("Loading ...");

    /**
     * Shows the Dialog.
     * @param parent The Frame to which the dialog will be associated
     * @return a List of String that are S3 bucket keys.
     */
    public static List<String> showDialog(Component parent) {

        accountList.removeAllElements();
        accountMap.clear();
        selectedKeys.clear();

        getAliases();
        getAccounts();

        Frame frame = JOptionPane.getFrameForComponent(parent);
        dialog = new S3FileChooser(frame);
        dialog.setVisible(true);

        return selectedKeys;
    }

    ////////////////////////////////////////////////////////////////////////////
    // ActionListener
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void actionPerformed(ActionEvent e) {

        if ("Load".equals(e.getActionCommand())) {
            addSelectedKeys();
        }

        StringBuilder query = new StringBuilder();
        query.append("UPDATE aws_credentials SET aws_prefix =");
        query.append(" '").append(currentAccount.getPrefix()).append("'");
        query.append(" WHERE id = ").append(currentAccount.getId());
        DbManager.getInstance().doInsertUpdate(query.toString());

        S3FileChooser.dialog.setVisible(false);
    }

    ////////////////////////////////////////////////////////////////////////////
    // Private methods
    ////////////////////////////////////////////////////////////////////////////
    private static void getAliases() {

        aliasMap.clear();

        String query = "SELECT aws_account, aws_alias FROM aws_alias";
        List<ResultSetRow> rows = DbManager.getInstance().executeCursorStatement(query);
        for (ResultSetRow row : rows) {

            String aws_acct = (String) row.get("aws_account");
            String aws_alias = (String) row.get("aws_alias");

            aliasMap.put(aws_acct, aws_alias);
        }
    }

    private static void getAccounts() {

        String query = "SELECT * FROM aws_credentials";
        List<ResultSetRow> rows = DbManager.getInstance().executeCursorStatement(query);
        for (ResultSetRow row : rows) {

            String name = (String) row.get("aws_name");

            AwsAccount account = new AwsAccount((Integer) row.get("id"), name, (String) row.get("aws_bucket"),
                    (String) row.get("aws_key"), (String) row.get("aws_secret"), (String) row.get("aws_prefix"));

            accountMap.put(name, account);
            accountList.addElement(name);
            currentAccount = account;
        }

        prefix = currentAccount.getPrefix();
    }

    private S3FileChooser(Frame frame) {

        super(frame, "S3 File Browser", true);

        final JButton btnLoad = new JButton("Load");
        btnLoad.setActionCommand("Load");
        btnLoad.addActionListener(this);
        getRootPane().setDefaultButton(btnLoad);

        JButton btnCancel = new JButton("Cancel");
        btnCancel.addActionListener(this);

        s3ListModel.clear();
        s3List = new JList(s3ListModel);
        s3List.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent mouseEvent) {

                if (mouseEvent.getClickCount() == 2) {

                    handleDoubleClickEvent();

                } else if (mouseEvent.getClickCount() == 1) {

                    String selected = ((S3ListModel) s3List.getSelectedValue()).getPath();

                    if (selected.contains("/")) {
                        btnLoad.setEnabled(false);
                    } else {
                        btnLoad.setEnabled(true);
                    }
                }
            }
        });

        s3List.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        s3List.setLayoutOrientation(JList.VERTICAL);
        s3List.setVisibleRowCount(-1);
        s3List.setCellRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                    boolean cellHasFocus) {

                JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected,
                        cellHasFocus);

                S3ListModel model = (S3ListModel) value;

                if (model.getFileType() == S3ListModel.FILE_DIR) {
                    label.setIcon(UIManager.getIcon("FileView.directoryIcon"));
                } else if (model.getFileType() == S3ListModel.FILE_DOC) {
                    label.setIcon(UIManager.getIcon("FileView.fileIcon"));
                }

                label.setText(model.getAlias());

                return label;
            }
        });

        JScrollPane listScroller = new JScrollPane(s3List);
        listScroller.setPreferredSize(new Dimension(400, 480));
        listScroller.setAlignmentX(LEFT_ALIGNMENT);

        JPanel listPane = new JPanel();
        listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
        listPane.add(Box.createRigidArea(new Dimension(0, 5)));
        listPane.add(listScroller);
        listPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        //Lay out the buttons from left to right.
        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
        buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
        buttonPane.add(loadingLabel);
        buttonPane.add(Box.createHorizontalGlue());
        buttonPane.add(btnCancel);
        buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
        buttonPane.add(btnLoad);

        //Put everything together, using the content pane's BorderLayout.
        Container contentPane = getContentPane();
        contentPane.add(getToolbar(), BorderLayout.PAGE_START);
        contentPane.add(listPane, BorderLayout.CENTER);
        contentPane.add(buttonPane, BorderLayout.PAGE_END);

        //Initialize values.
        pack();
        setLocationRelativeTo(frame);

        SwingWorker worker = new SwingWorker<Void, Void>() {

            @Override
            public Void doInBackground() {
                reloadContents();
                return null;
            };
        };

        worker.execute();
    }

    private void handleDoubleClickEvent() {

        String selected = ((S3ListModel) s3List.getSelectedValue()).getPath();

        if (selected.equalsIgnoreCase(MOVE_BACK)) {

            // update prefix and reload
            int lastSlash = prefix.lastIndexOf("/");
            String tmpPrefix = prefix.substring(0, lastSlash);

            if (tmpPrefix.contains("/")) {

                lastSlash = tmpPrefix.lastIndexOf("/") + 1;
                prefix = tmpPrefix.substring(0, lastSlash);

            } else {
                prefix = "";
            }

            reloadContents();

        } else {

            int firstSlash = selected.indexOf("/");
            if (firstSlash == 0) {
                selected = selected.substring(1, selected.length());
            }

            int lastSlash = selected.lastIndexOf("/") + 1;
            if (lastSlash == selected.length()) {

                prefix = prefix + selected;
                reloadContents();
            } else {
                addSelectedKeys();

                currentAccount.setPrefix(prefix);
                S3FileChooser.dialog.setVisible(false);
            }
        }
    }

    private void reloadContents() {

        loadingLabel.setVisible(true);
        this.s3ListModel.clear();

        String bucketName = currentAccount.getBucket();

        ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
        listObjectsRequest.setBucketName(bucketName);
        listObjectsRequest.setPrefix(prefix);
        listObjectsRequest.setDelimiter("/");

        AWSCredentials credentials = new BasicAWSCredentials(currentAccount.getKey(), currentAccount.getSecret());

        AmazonS3 s3Client = new AmazonS3Client(credentials);

        try {
            ObjectListing objectListing = s3Client.listObjects(listObjectsRequest);

            // Add .. if not at root
            if (prefix.trim().length() != 0) {
                S3ListModel model = new S3ListModel(MOVE_BACK, MOVE_BACK, S3ListModel.FILE_BACK);
                this.s3ListModel.addElement(model);
            }

            // these are directories
            List<String> directories = objectListing.getCommonPrefixes();
            for (String directory : directories) {

                String dir = stripPrefix(directory);
                int lastSlash = dir.lastIndexOf("/");
                String strippeDir = dir.substring(0, lastSlash);

                String alias = dir;
                if (isAccountNumber(strippeDir)) {
                    if (aliasMap.containsKey(strippeDir)) {
                        alias = aliasMap.get(strippeDir);
                    }
                }

                S3ListModel model = new S3ListModel(dir, alias, S3ListModel.FILE_DIR);
                this.s3ListModel.addElement(model);
            }

            // these are files
            List<S3ObjectSummary> objectSummaries = objectListing.getObjectSummaries();
            for (final S3ObjectSummary objectSummary : objectSummaries) {

                String file = stripPrefix(objectSummary.getKey());

                S3ListModel model = new S3ListModel(file, file, S3ListModel.FILE_DOC);
                this.s3ListModel.addElement(model);
            }

            loadingLabel.setVisible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String stripPrefix(String key) {

        String stripped = key;

        if (S3FileChooser.prefix.trim().length() > 0) {

            int prefixLength = S3FileChooser.prefix.length() - 1;
            stripped = key.substring(prefixLength, key.length());

            int firstSlash = stripped.indexOf("/");
            if (firstSlash == 0) {
                stripped = stripped.substring(1, stripped.length());
            }
        }

        return stripped;
    }

    private void addSelectedKeys() {

        List<S3ListModel> selectedItems = s3List.getSelectedValuesList();
        for (S3ListModel key : selectedItems) {
            selectedKeys.add(S3FileChooser.prefix + key.getPath());
        }
    }

    private JToolBar getToolbar() {

        JToolBar toolbar = new JToolBar();
        toolbar.setFloatable(false);

        JButton btnHome = new JButton();
        ToolBarUtils.addImageToButton(btnHome, "Home-32.png", "Home", "Home");
        btnHome.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent mouseEvent) {
                prefix = "";
                reloadContents();
            }
        });
        toolbar.add(btnHome);

        JComboBox accountCombo = new JComboBox(accountList);
        accountCombo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JComboBox cb = (JComboBox) e.getSource();
                String newSelection = (String) cb.getSelectedItem();

                if (newSelection != null) {
                    currentAccount = accountMap.get(newSelection);
                    String update = "UPDATE aws_credentials SET active = 0";
                    DbManager.getInstance().doInsertUpdate(update);

                    String setActive = "UPDATE aws_credentials SET active = 1 WHERE ID = " + currentAccount.getId();
                    DbManager.getInstance().doInsertUpdate(setActive);

                    prefix = currentAccount.getPrefix();
                    reloadContents();
                }
            }
        });

        toolbar.add(accountCombo);

        return toolbar;
    }

    private boolean isAccountNumber(String accountnumber) {

        boolean isAccountNumber = false;

        if (accountnumber.length() == 12) {

            try {
                Long.parseLong(accountnumber);
                isAccountNumber = true;
            } catch (Exception e) {
            }
        }

        return isAccountNumber;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Model class
    ////////////////////////////////////////////////////////////////////////////
    class S3ListModel {

        public static final int FILE_BACK = 0;
        public static final int FILE_DIR = 1;
        public static final int FILE_DOC = 2;

        private final String path;
        private final String alias;
        private final int fileType;

        S3ListModel(String path, String alias, int fileType) {
            this.path = path;
            this.alias = alias;
            this.fileType = fileType;
        }

        public String getPath() {
            return this.path;
        }

        public String getAlias() {
            return this.alias;
        }

        public int getFileType() {
            return this.fileType;
        }
    }
}