Java tutorial
/******************************************************************************* * PGPTool is a desktop application for pgp encryption/decryption * Copyright (C) 2017 Sergey Karpushin * * 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 org.pgptool.gui.ui.importkey; import static org.pgptool.gui.app.Messages.text; import java.awt.event.ActionEvent; import java.io.File; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.Action; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; import org.pgptool.gui.app.EntryPoint; import org.pgptool.gui.app.Messages; import org.pgptool.gui.configpairs.api.ConfigPairs; import org.pgptool.gui.encryption.api.KeyFilesOperations; import org.pgptool.gui.encryption.api.KeyRingService; import org.pgptool.gui.encryption.api.dto.Key; import org.pgptool.gui.tools.ConsoleExceptionUtils; import org.pgptool.gui.ui.keyslist.ComparatorKeyByNameImpl; import org.pgptool.gui.ui.keyslist.KeysTableModel; import org.pgptool.gui.ui.keyslist.KeysTablePm; import org.pgptool.gui.ui.tools.UiUtils; import org.pgptool.gui.ui.tools.browsefs.MultipleFilesChooserDialog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import com.google.common.base.Preconditions; import ru.skarpushin.swingpm.base.PresentationModelBase; import ru.skarpushin.swingpm.base.View; import ru.skarpushin.swingpm.modelprops.table.ModelTableProperty; import ru.skarpushin.swingpm.modelprops.table.ModelTablePropertyAccessor; import ru.skarpushin.swingpm.tools.actions.LocalizedAction; public class KeyImporterPm extends PresentationModelBase { private static Logger log = Logger.getLogger(KeyImporterPm.class); private static final String BROWSE_FOLDER = "KeyImporterPm.BROWSE_FOLDER"; private static final String[] EXTENSIONS = new String[] { "asc", "bpg" }; @Autowired private ConfigPairs appProps; @Autowired // @Resource(name = "keyFilesOperations") private KeyFilesOperations keyFilesOperations; @Autowired // @Resource(name = "keyRingService") private KeyRingService keyRingService; private KeyImporterHost host; private ModelTableProperty<Key> keys; private MultipleFilesChooserDialog sourceFileChooser; private Comparator<Key> keySorterByNameAsc = new ComparatorKeyByNameImpl(); public boolean init(KeyImporterHost host) { Preconditions.checkArgument(host != null); this.host = host; initModelProperties(); File[] filesToLoad = null; if ((filesToLoad = getSourceFileChooser().askUserForMultipleFiles()) == null) { return false; } if (!loadKey(filesToLoad)) { return false; } return true; } private void initModelProperties() { actionDoImport.setEnabled(false); keys = new ModelTableProperty<>(this, new ArrayList<>(), "keys", new KeysTableModel()); } @Override public void registerView(View<?> view) { super.registerView(view); Preconditions.checkState(host != null); } public MultipleFilesChooserDialog getSourceFileChooser() { if (sourceFileChooser == null) { sourceFileChooser = new MultipleFilesChooserDialog(findRegisteredWindowIfAny(), appProps, BROWSE_FOLDER) { @Override protected void doFileChooserPostConstruct(JFileChooser ofd) { super.doFileChooserPostConstruct(ofd); ofd.setDialogTitle(Messages.get("action.importKey")); ofd.setAcceptAllFileFilterUsed(false); ofd.addChoosableFileFilter(keyFilesFilter); ofd.addChoosableFileFilter(ofd.getAcceptAllFileFilter()); ofd.setFileFilter(ofd.getChoosableFileFilters()[0]); } private FileFilter keyFilesFilter = new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory() || !f.isFile()) { return true; } if (!isExtension(f.getName(), EXTENSIONS)) { return false; } // NOTE: Although it gives best results -- I have a // slight concern that this might be too heavy operation // to perform thorough -- check for each file // contents. My hope is that since we're checking only // key files it shouldn't be a problem. Non-key files // with same xtensions will not take a long time to fail try { Key readKey = keyFilesOperations.readKeyFromFile(f.getAbsolutePath()); Preconditions.checkState(readKey != null, "Key wasn't parsed"); Key existingKey = keyRingService.findKeyById(readKey.getKeyInfo().getKeyId()); if (existingKey == null) { return true; } if (!existingKey.getKeyData().isCanBeUsedForDecryption() && readKey.getKeyData().isCanBeUsedForDecryption()) { return true; } return false; } catch (Throwable t) { // in this case it's not an issue. So it's debug // level log.debug( "File is not accepte for file chooser becasue was not able to read it as a key", t); } return false; } private boolean isExtension(String fileName, String[] extensions) { String extension = FilenameUtils.getExtension(fileName); if (!StringUtils.hasText(extension)) { return false; } for (String ext : extensions) { if (ext.equalsIgnoreCase(extension)) { return true; } } return false; } @Override public String getDescription() { return "Key files (.asc, .bpg)"; } }; }; } return sourceFileChooser; } private boolean loadKey(File[] filesToLoad) { try { Map<String, Throwable> exceptions = new HashMap<>(); List<Key> loadedKeys = loadKeysSafe(filesToLoad, exceptions); if (exceptions.size() > 0) { String msg = buildSummaryMessage("error.keysLoadedStatistics", loadedKeys.size(), exceptions); UiUtils.messageBox(null, msg, Messages.get("term.attention"), JOptionPane.ERROR_MESSAGE); } if (loadedKeys.size() > 0) { loadedKeys.sort(keySorterByNameAsc); keys.getList().addAll(loadedKeys); actionDoImport.setEnabled(true); return true; } } catch (Throwable t) { EntryPoint.reportExceptionToUser("exception.failedToReadKey", t); } return false; } private List<Key> loadKeysSafe(File[] filesToLoad, Map<String, Throwable> exceptions) { List<Key> ret = new ArrayList<>(filesToLoad.length); for (File keyFile : filesToLoad) { try { Key key = keyFilesOperations.readKeyFromFile(keyFile.getAbsolutePath()); ret.add(key); } catch (Throwable t) { log.warn("Failed to read key file", t); exceptions.put(keyFile.toString(), t); } } return ret; } private String buildSummaryMessage(String messageCode, int successCount, Map<String, Throwable> exceptions) { StringBuilder sb = new StringBuilder(); sb.append(text(messageCode, successCount, exceptions.size())); sb.append("\n"); for (Entry<String, Throwable> exc : exceptions.entrySet()) { sb.append("\n"); sb.append(exc.getKey()); sb.append("\n"); sb.append(ConsoleExceptionUtils.getAllMessages(exc.getValue())); sb.append("\n"); } return sb.toString(); } @SuppressWarnings("serial") private Action actionDoImport = new LocalizedAction("action.import") { @Override public void actionPerformed(ActionEvent e) { try { Preconditions.checkState(keys.getList().size() > 0, "No keys loaded"); Map<String, Throwable> exceptions = new HashMap<>(); int loadedCount = importKeysSafe(exceptions); if (exceptions.size() > 0) { String msg = buildSummaryMessage("error.keysImportStatistics", loadedCount, exceptions); UiUtils.messageBox(null, msg, Messages.get("term.attention"), JOptionPane.ERROR_MESSAGE); } host.handleImporterFinished(); } catch (Throwable t) { log.error("Failed to import keys", t); EntryPoint.reportExceptionToUser("exception.failedToImportPgpKey", t); return; } } private int importKeysSafe(Map<String, Throwable> exceptions) { int loadedCount = 0; for (Key key : keys.getList()) { try { keyRingService.addKey(key); loadedCount++; } catch (Throwable t) { log.warn("Failed to import key " + key.getKeyInfo().getUser(), t); exceptions.put(key.getKeyInfo().getUser(), t); } } return loadedCount; } }; @SuppressWarnings("serial") private Action actionCancel = new LocalizedAction("action.cancel") { @Override public void actionPerformed(ActionEvent e) { host.handleImporterFinished(); } }; private KeysTablePm keysTablePm = new KeysTablePm() { @Override public ModelTablePropertyAccessor<Key> getKeys() { return keys.getModelTablePropertyAccessor(); } }; protected Action getActionCancel() { return actionCancel; } protected Action getActionDoImport() { return actionDoImport; } public KeysTablePm getKeysTablePm() { return keysTablePm; } }