de.willuhn.jameica.hbci.passports.pintan.Controller.java Source code

Java tutorial

Introduction

Here is the source code for de.willuhn.jameica.hbci.passports.pintan.Controller.java

Source

/**********************************************************************
 *
 * Copyright (c) 2004 Olaf Willuhn
 * All rights reserved.
 * 
 * This software is copyrighted work licensed under the terms of the
 * Jameica License.  Please consult the file "LICENSE" for details. 
 *
 **********************************************************************/
package de.willuhn.jameica.hbci.passports.pintan;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.TerminalFactory;

import org.apache.commons.lang.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.kapott.hbci.passport.AbstractHBCIPassport;
import org.kapott.hbci.passport.HBCIPassport;

import de.willuhn.jameica.gui.AbstractControl;
import de.willuhn.jameica.gui.AbstractView;
import de.willuhn.jameica.gui.Action;
import de.willuhn.jameica.gui.GUI;
import de.willuhn.jameica.gui.input.CheckboxInput;
import de.willuhn.jameica.gui.input.Input;
import de.willuhn.jameica.gui.input.IntegerInput;
import de.willuhn.jameica.gui.input.SelectInput;
import de.willuhn.jameica.gui.input.TextInput;
import de.willuhn.jameica.gui.parts.CheckedContextMenuItem;
import de.willuhn.jameica.gui.parts.ContextMenu;
import de.willuhn.jameica.gui.parts.ContextMenuItem;
import de.willuhn.jameica.gui.parts.TablePart;
import de.willuhn.jameica.hbci.HBCI;
import de.willuhn.jameica.hbci.HBCIProperties;
import de.willuhn.jameica.hbci.gui.action.PassportChange;
import de.willuhn.jameica.hbci.gui.action.PassportTest;
import de.willuhn.jameica.hbci.gui.dialogs.PassportPropertyDialog;
import de.willuhn.jameica.hbci.gui.input.BLZInput;
import de.willuhn.jameica.hbci.gui.input.HBCIVersionInput;
import de.willuhn.jameica.hbci.passport.PassportChangeRequest;
import de.willuhn.jameica.hbci.passports.pintan.rmi.PinTanConfig;
import de.willuhn.jameica.hbci.passports.pintan.server.PassportHandleImpl;
import de.willuhn.jameica.hbci.rmi.Konto;
import de.willuhn.jameica.messaging.StatusBarMessage;
import de.willuhn.jameica.system.Application;
import de.willuhn.jameica.system.OperationCanceledException;
import de.willuhn.logging.Level;
import de.willuhn.logging.Logger;
import de.willuhn.util.ApplicationException;
import de.willuhn.util.I18N;

/**
 * Controller, der die Eingaben zur Konfiguration des Passports handelt.
 */
public class Controller extends AbstractControl {

    private final static I18N i18n = Application.getPluginLoader().getPlugin(HBCI.class).getResources().getI18N();

    private PinTanConfig config = null;
    private HBCIPassport passport = null;

    private TablePart configList = null;

    private Input url = null;
    private Input blz = null;
    private Input port = null;
    private Input filterType = null;
    private Input hbciVersion = null;
    private Input customerId = null;
    private Input userId = null;
    private Input bezeichnung = null;
    private CheckboxInput showTan = null;
    private SelectInput cardReaders = null;
    private CheckboxInput useUsb = null;

    // BUGZILLA 173
    private TablePart kontoList = null;

    /**
     * ct.
     * @param view
     */
    public Controller(AbstractView view) {
        super(view);
    }

    /**
     * Liefert die aktuelle Config.
     * @return config
     */
    public PinTanConfig getConfig() {
        if (config == null)
            config = (PinTanConfig) getCurrentObject();
        return config;
    }

    /**
     * Liefert eine Liste mit den existierenden Konfigurationen.
     * @return Liste der Konfigurationen.
     * @throws RemoteException
     */
    public TablePart getConfigList() throws RemoteException {
        if (configList != null)
            return configList;

        configList = new TablePart(PinTanConfigFactory.getConfigs(), new Action() {
            public void handleAction(Object context) throws ApplicationException {
                GUI.startView(Detail.class, context);
            }
        });

        configList.addColumn(i18n.tr("Name der Bank"), "bank");
        configList.addColumn(i18n.tr("Alias-Name"), "bezeichnung");
        configList.addColumn(i18n.tr("Bankleitzahl"), "blz");
        configList.addColumn(i18n.tr("URL"), "url");

        ContextMenu ctx = new ContextMenu();

        ctx.addItem(new CheckedContextMenuItem(i18n.tr("ffnen"), new Action() {
            public void handleAction(Object context) throws ApplicationException {
                if (context == null)
                    return;
                try {
                    GUI.startView(Detail.class, context);
                } catch (Exception e) {
                    Logger.error("error while loading config", e);
                    GUI.getStatusBar().setErrorText(i18n.tr("Fehler beim Anlegen der Konfiguration"));
                }
            }
        }, "document-open.png"));

        ctx.addItem(new ContextMenuItem(i18n.tr("PIN/TAN-Zugang anlegen"), new Action() {
            public void handleAction(Object context) throws ApplicationException {
                handleCreate();
            }
        }, "document-new.png"));

        ctx.addItem(ContextMenuItem.SEPARATOR);
        ctx.addItem(new CheckedContextMenuItem(i18n.tr("Lschen..."), new Action() {
            public void handleAction(Object context) throws ApplicationException {
                handleDelete((PinTanConfig) context);
            }
        }, "user-trash-full.png"));

        configList.setContextMenu(ctx);
        configList.setMulti(false);
        configList.setRememberColWidths(true);
        configList.setRememberOrder(true);
        configList.setSummary(false);

        return configList;
    }

    /**
     * Liefert ein Eingabe-Feld fuer die BLZ.
     * @return BLZ
     * @throws RemoteException
     */
    public Input getBLZ() throws RemoteException {
        if (this.blz != null)
            return this.blz;
        this.blz = new BLZInput(getConfig().getBLZ());
        this.blz.setEnabled(false);
        this.blz.setName(i18n.tr("Bankleitzahl"));
        this.blz.setMandatory(true);
        return this.blz;
    }

    /**
     * BUGZILLA 173
     * BUGZILLA 314
     * Liefert eine Tabelle mit festzuordenbaren Konten.
     * @return Auswahl-Feld.
     * @throws RemoteException
     */
    public TablePart getKontoAuswahl() throws RemoteException {
        if (kontoList == null)
            this.kontoList = new KontoList(this.getConfig());
        return kontoList;
    }

    /**
     * Liefert ein Eingabe-Feld fuer die URL.
     * @return URL
     * @throws RemoteException
     */
    public Input getURL() throws RemoteException {
        if (url != null)
            return url;
        url = new TextInput(getConfig().getURL());
        url.setEnabled(false);
        url.setName(i18n.tr("URL des Bank-Servers"));
        url.setMandatory(true);
        return url;
    }

    /**
     * Liefert eine Checkbox zur Aktivierung oder Deaktivierung der TAN-Anzeige waehrend der Eingabe.
     * @return Checkbox.
     * @throws RemoteException
     */
    public CheckboxInput getShowTan() throws RemoteException {
        if (showTan != null)
            return showTan;
        showTan = new CheckboxInput(getConfig().getShowTan());
        return showTan;
    }

    /**
     * Liefert eine Auswahl verfuegbarer Kartenleser-Bezeichnungen.
     * @return eine Auswahl verfuegbaren Kartenleser-Bezeichnungen.
     * @throws RemoteException
     */
    public SelectInput getCardReaders() throws RemoteException {
        if (this.cardReaders != null)
            return this.cardReaders;

        List<String> available = new ArrayList<String>();

        // Erste Zeile Leerer Eintrag.
        // Damit das Feld auch dann leer bleiben kann, wenn der User nur einen
        // Kartenleser hat. Der sollte dann nicht automatisch vorselektiert
        // werden, da dessen Bezeichnung sonst unnoetigerweise hart gespeichert wird
        available.add("");
        try {
            TerminalFactory terminalFactory = TerminalFactory.getDefault();
            CardTerminals terminals = terminalFactory.terminals();
            if (terminals != null) {
                List<CardTerminal> list = terminals.list();
                if (list != null && list.size() > 0) {
                    for (CardTerminal t : list) {
                        String name = StringUtils.trimToNull(t.getName());
                        if (name != null)
                            available.add(name);
                    }
                }
            }
        } catch (Throwable t) {
            Logger.info("unable to determine card reader list: " + t.getMessage());
            Logger.write(Level.DEBUG, "stacktrace for debugging purpose", t);
        }

        this.cardReaders = new SelectInput(available, this.getConfig().getCardReader());
        this.cardReaders.setEditable(true);
        this.cardReaders.setComment(i18n.tr("nur ntig, wenn mehrere Leser vorhanden"));
        this.cardReaders.setName(i18n.tr("Identifier des PC/SC-Kartenlesers"));
        return this.cardReaders;
    }

    /**
     * Liefert eine Checkbox, mit der eingestellt werden kann, ob chipTAN USB verwendet werden soll.
     * @return eine Checkbox, mit der eingestellt werden kann, ob chipTAN USB verwendet werden soll.
     * @throws RemoteException
     */
    public CheckboxInput getChipTANUSB() throws RemoteException {
        if (this.useUsb != null)
            return this.useUsb;

        final Boolean b = this.getConfig().isChipTANUSB();
        this.useUsb = new CheckboxInput(b == null || b.booleanValue());
        this.useUsb.setName(i18n.tr("Kartenleser per USB zur TAN-Erzeugung verwenden"));

        final Listener l = new Listener() {

            @Override
            public void handleEvent(Event event) {
                try {
                    Boolean newValue = (Boolean) getChipTANUSB().getValue();

                    if (event != null && event.type == SWT.Selection) {
                        // Wir kamen aus dem Gray-State. Der User hat entschieden
                        org.eclipse.swt.widgets.Button bt = (org.eclipse.swt.widgets.Button) useUsb.getControl();
                        if (bt.getGrayed()) {
                            bt.setGrayed(false);
                            bt.setSelection(true);
                            newValue = Boolean.TRUE;
                        }
                    }

                    if (event != null)
                        getCardReaders().setEnabled(newValue != null && newValue.booleanValue());
                    else
                        getCardReaders().setEnabled(b != null && b.booleanValue());

                    // Bei chipTAN USB wird die TAN grundsaetzlich angezeigt
                    if (newValue != null && newValue.booleanValue()
                            && (event == null || event.type == SWT.Selection)) {
                        Boolean showTan = (Boolean) getShowTan().getValue();
                        if (showTan == null || !showTan.booleanValue()) {
                            getShowTan().setValue(true);
                            String msg = i18n.tr(
                                    "Anzeige der TANs aktiviert, damit Sie die korrekte bertragung vom Kartenleser prfen knnen");
                            Application.getMessagingFactory()
                                    .sendMessage(new StatusBarMessage(msg, StatusBarMessage.TYPE_INFO));
                        }
                    }
                } catch (RemoteException re) {
                    Logger.error("error while updating cardreader field", re);
                }
            }
        };

        // einmal initial ausloesen
        l.handleEvent(null);

        this.useUsb.addListener(l);
        return this.useUsb;
    }

    /**
     * Liefert ein Eingabe-Feld fuer die Bezeichnung.
     * @return Bezeichnung.
     * @throws RemoteException
     */
    public Input getBezeichnung() throws RemoteException {
        if (bezeichnung != null)
            return bezeichnung;
        bezeichnung = new TextInput(getConfig().getBezeichnung());
        bezeichnung.setComment(i18n.tr("Angabe optional"));
        bezeichnung.setName(i18n.tr("Alias-Name"));
        return bezeichnung;
    }

    /**
     * Liefert ein Eingabe-Feld fuer den TCP-Port.
     * @return Port
     * @throws RemoteException
     */
    public Input getPort() throws RemoteException {
        if (port != null)
            return port;
        port = new IntegerInput(getConfig().getPort());
        port.setName(i18n.tr("TCP-Port des Bank-Servers"));
        port.setMandatory(true);
        return port;
    }

    /**
     * Liefert ein Eingabe-Feld fuer die Benutzerkennung.
     * @return Benutzerkennung.
     * @throws RemoteException
     */
    public Input getCustomerId() throws RemoteException {
        if (customerId != null)
            return customerId;
        customerId = new TextInput(getConfig().getCustomerId(), 20);
        customerId.setName(i18n.tr("Kundenkennung"));
        customerId.setMandatory(true);
        return customerId;
    }

    /**
     * Liefert ein Eingabe-Feld fuer die Userkennung.
     * @return Userkennung.
     * @throws RemoteException
     */
    public Input getUserId() throws RemoteException {
        if (userId != null)
            return userId;
        userId = new TextInput(getConfig().getUserId(), 20);
        userId.setName(i18n.tr("Benutzerkennung"));
        userId.setMandatory(true);
        return userId;
    }

    /**
     * Liefert ein Eingabe-Feld fuer den Transport-Filter.
     * @return Filter
     * @throws RemoteException
     */
    public Input getFilterType() throws RemoteException {
        if (filterType != null)
            return filterType;
        filterType = new SelectInput(new String[] { "Base64", "None" }, getConfig().getFilterType());
        filterType.setComment(i18n.tr("meist Base64"));
        filterType.setName(i18n.tr("Filter fr bertragung"));
        filterType.setMandatory(true);
        return filterType;
    }

    /**
     * Liefert eine Auswahl-Box fuer die HBCI-Version.
     * @return Auswahl-Box.
     * @throws RemoteException
     */
    public Input getHBCIVersion() throws RemoteException {
        if (hbciVersion != null)
            return hbciVersion;
        String current = getConfig().getHBCIVersion();
        hbciVersion = new HBCIVersionInput(getHBCIPassport(), current);
        hbciVersion.setMandatory(true);
        hbciVersion.setName(i18n.tr("HBCI-Version"));
        return hbciVersion;
    }

    /**
     * Liefert den HBCI-Passport.
     * @return der HBCI-Passport.
     * @throws RemoteException
     */
    private HBCIPassport getHBCIPassport() throws RemoteException {
        if (this.passport == null) {
            // this.passport = PinTanConfigFactory.load(new File(config.getFilename()));
            // Mit obiger Zeile haben wir den Passport doppelt geoeffnet. In der Config haben wir ja schon eine Instanz
            this.passport = this.config.getPassport();
        }
        return this.passport;
    }

    /**
     * BUGZILLA 218
     * Loescht die Vorauswahlen bei den TAN-Verfahren.
     */
    public void handleDeleteTanSettings() {
        try {
            PinTanConfig conf = this.getConfig();
            conf.setCurrentSecMech(null);
            conf.setStoredSecMech(null);
            conf.setTanMedia(null);
            conf.setChipTANUSB(null);

            Application.getMessagingFactory().sendMessage(new StatusBarMessage(
                    i18n.tr("Vorauswahl der TAN-Verfahren zurckgesetzt"), StatusBarMessage.TYPE_SUCCESS));
        } catch (Exception e) {
            Logger.error("error while deleting tan settings", e);
            Application.getMessagingFactory().sendMessage(new StatusBarMessage(
                    i18n.tr("Fehler beim Zurcksetzen der TAN-Verfahren"), StatusBarMessage.TYPE_ERROR));
        }
    }

    /**
     * Zeigt die BPD/UPD des Passports an.
     */
    public synchronized void handleDisplayProperties() {
        try {
            new PassportPropertyDialog(PassportPropertyDialog.POSITION_CENTER, this.getHBCIPassport()).open();
        } catch (OperationCanceledException oce) {
            Logger.info("operation cancelled");
        } catch (ApplicationException e) {
            Application.getMessagingFactory()
                    .sendMessage(new StatusBarMessage(i18n.tr(e.getMessage()), StatusBarMessage.TYPE_ERROR));
        } catch (Throwable t) {
            Logger.error("error while displaying BPD/UPD", t);
            Application.getMessagingFactory().sendMessage(
                    new StatusBarMessage(i18n.tr("Fehler Anzeigen der BPD/UPD"), StatusBarMessage.TYPE_ERROR));
        }
    }

    /**
     * Loescht die Config.
     * @param config die zu loeschende Config.
     */
    public synchronized void handleDelete(PinTanConfig config) {
        if (config == null)
            return;
        try {
            if (!Application.getCallback().askUser(i18n.tr("Wollen Sie diese Konfiguration wirklich lschen?")))
                return;

            PinTanConfigFactory.delete(config);
            GUI.startView(View.class, null);
            Application.getMessagingFactory().sendMessage(
                    new StatusBarMessage(i18n.tr("Konfiguration gelscht"), StatusBarMessage.TYPE_SUCCESS));
        } catch (OperationCanceledException oce) {
            Logger.info("operation cancelled");
        } catch (ApplicationException ae) {
            Application.getMessagingFactory()
                    .sendMessage(new StatusBarMessage(ae.getMessage(), StatusBarMessage.TYPE_ERROR));
        } catch (Exception e) {
            Logger.error("error while deleting config", e);
            Application.getMessagingFactory().sendMessage(new StatusBarMessage(
                    i18n.tr("Lschen fehlgeschlagen: {0}", e.getMessage()), StatusBarMessage.TYPE_ERROR));
        }
    }

    /**
     * Testet die Konfiguration.
     */
    public synchronized void handleTest() {

        // Speichern, damit sicher ist, dass wir vernuenftige Daten fuer den
        // Test haben und die auch gespeichert sind
        if (!handleStore())
            return;

        try {
            new PassportTest().handleAction(new PassportHandleImpl(getConfig()));
        } catch (ApplicationException ae) {
            GUI.getStatusBar().setErrorText(ae.getMessage());
        } catch (RemoteException e) {
            Logger.error("error while testing passport", e);
            GUI.getStatusBar()
                    .setErrorText(i18n.tr("Fehler beim Testen der Konfiguration. Bitte prfen Sie das Protokoll. ")
                            + e.getMessage());
        }
    }

    /**
     * Erstellt eine neue Config.
     */
    public synchronized void handleCreate() {
        PinTanConfig conf = null;
        try {
            Logger.info("creating new pin/tan config");
            conf = PinTanConfigFactory.create();
            GUI.startView(Detail.class, conf);

            GUI.getStatusBar().setSuccessText(
                    i18n.tr("Konfiguration erfolgreich erstellt. Bitte klicken Sie \"Speichern\" zum bernehmen."));
        } catch (ApplicationException e) {
            Logger.error("error while creating config", e);
            GUI.getStatusBar().setErrorText(i18n.tr(e.getMessage()));
        } catch (Throwable t) {
            // Fehlertext nur anzeigen, wenn der Vorgang nicht durch den User abgebrochen wurde
            if (HBCIProperties.getCause(t, OperationCanceledException.class) == null) {
                Logger.error("error while creating config", t);
                GUI.getStatusBar().setErrorText(i18n.tr("Fehler beim Erstellen der Konfiguration"));
            }
        }
    }

    /**
     * Speichert die Konfiguration.
     * @return true, wenn die Config gespeichert werden konnte.
     */
    public synchronized boolean handleStore() {
        try {
            Logger.info("storing pin/tan config");

            PinTanConfig config = getConfig();

            Konto[] konten = null;
            List checked = getKontoAuswahl().getItems();
            if (checked != null && checked.size() > 0)
                konten = (Konto[]) checked.toArray(new Konto[checked.size()]);
            config.setKonten(konten);

            String version = (String) getHBCIVersion().getValue();
            config.setFilterType((String) getFilterType().getValue());
            config.setBezeichnung((String) getBezeichnung().getValue());
            config.setShowTan(((Boolean) getShowTan().getValue()).booleanValue());
            config.setHBCIVersion(version);
            config.setPort((Integer) getPort().getValue());
            config.setCardReader((String) getCardReaders().getValue());

            PtSecMech secMech = config.getCurrentSecMech();
            if (secMech != null && secMech.useUSB()) {
                CheckboxInput check = this.getChipTANUSB();
                Button button = (Button) check.getControl();
                if (button != null && !button.isDisposed()) {
                    boolean gray = button.getGrayed();
                    config.setChipTANUSB((Boolean) (gray ? null : check.getValue()));
                }
            }

            AbstractHBCIPassport p = (AbstractHBCIPassport) config.getPassport();
            PassportChangeRequest change = new PassportChangeRequest(p, (String) getCustomerId().getValue(),
                    (String) getUserId().getValue());
            new PassportChange().handleAction(change);

            if (getHBCIVersion().hasChanged()) {
                // Das triggert beim naechsten Verbindungsaufbau
                // HBCIHandler.<clinit>
                // -> HBCIHandler.registerUser()
                // -> HBCIUser.register()
                // -> HBCIUser.updateUserData()
                // -> HBCIUser.fetchSysId() - und das holt die BPD beim naechsten mal ueber einen nicht-anonymen Dialog
                Logger.info("hbci version has changed to \"" + version
                        + "\" - set sysId to 0 to force BPD reload on next connect");
                Properties props = p.getBPD();
                if (props != null) {
                    props.remove("BPA.version");
                    p.syncSysId();
                }
            }

            PinTanConfigFactory.store(config);
            this.passport = null; // force reload

            GUI.getStatusBar().setSuccessText(i18n.tr("Konfiguration gespeichert"));
            return true;
        } catch (ApplicationException e) {
            Logger.error("error while storing config", e);
            GUI.getStatusBar().setErrorText(i18n.tr(e.getMessage()));
        } catch (Throwable t) {
            Logger.error("error while creating config", t);
            GUI.getStatusBar().setErrorText(i18n.tr("Fehler beim Speichern der Konfiguration"));
        }
        return false;
    }

}