Package org.kapott.hbci.manager

Source Code of org.kapott.hbci.manager.HBCIHandler

/*  $Id: HBCIHandler.java,v 1.2 2011/08/31 14:05:21 willuhn Exp $

    This file is part of HBCI4Java
    Copyright (C) 2001-2008  Stefan Palme

    HBCI4Java 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 2 of the License, or
    (at your option) any later version.

    HBCI4Java 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, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package org.kapott.hbci.manager;

import java.lang.reflect.Constructor;
import java.security.KeyPair;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.kapott.hbci.GV.GVTemplate;
import org.kapott.hbci.GV.HBCIJob;
import org.kapott.hbci.GV.HBCIJobImpl;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.exceptions.InvalidArgumentException;
import org.kapott.hbci.exceptions.InvalidUserDataException;
import org.kapott.hbci.passport.AbstractPinTanPassport;
import org.kapott.hbci.passport.HBCIPassport;
import org.kapott.hbci.passport.HBCIPassportInternal;
import org.kapott.hbci.status.HBCIDialogStatus;
import org.kapott.hbci.status.HBCIExecStatus;
import org.kapott.hbci.status.HBCIExecThreadedStatus;

/** <p>Ein Handle f�r genau einen HBCI-Zugang. Diese Klasse stellt das Verbindungsglied
    zwischen der Anwendung und dem HBCI-Kernel dar. F�r jeden HBCI-Zugang, den
    die Anwendung benutzt, muss ein entsprechender HBCI-Handler angelegt werden.
    Darin sind folgende Daten zusammengefasst:</p>
    <ul>
      <li>Ein {@link org.kapott.hbci.passport.HBCIPassport}, welches die Nutzeridentifikationsdaten
          sowie die Zugangsdaten zum entsprechenden HBCI-Server enth�lt</li>
      <li>Die zu benutzende HBCI-Versionsnummer</li>
      <li>interne Daten zur Verwaltung der Dialoge bei der Kommunikation
          mit dem HBCI-Server</li>
    </ul>
    <p>Alle Anfragen der Anwendung an den HBCI-Kernel laufen �ber einen solchen
    Handler, womit gleichzeit eindeutig festgelegt ist, welche HBCI-Verbindung
    diese Anfrage betrifft.</p>
    <p>Die prinzipielle Benutzung eines Handlers sieht in etwa wiefolgt aus:
    <pre>
// ...
HBCIPassport passport=AbstractHBCIPassport.getInstance();
HBCIHandler handle=new HBCIHandler(passport.getHBCIVersion(),passport);

HBCIJob jobSaldo=handle.newJob("SaldoReq");       // n�chster Auftrag ist Saldenabfrage
jobSaldo.setParam("number","1234567890");         // Kontonummer f�r Saldenabfrage
jobSaldo.addToQueue();

HBCIJob jobUeb=handle.newJob("Ueb");
jobUeb.setParam("src.number","1234567890");
jobUeb.setParam("dst.number","9876543210");
// ...
jobUeb.addToQueue();

// ...

HBCIExecStatus status=handle.execute();

// Auswerten von status
// Auswerten der einzelnen job-Ergebnisse

handle.close();
</pre> */
public final class HBCIHandler
  implements IHandlerData
{
    public final static int REFRESH_BPD=1;
    public final static int REFRESH_UPD=2;
   
    private HBCIKernelImpl       kernel;
    private HBCIPassportInternal passport;
    private Map<String, HBCIDialog>                  dialogs;
   
    /** Anlegen eines neuen HBCI-Handler-Objektes. Beim Anlegen wird
        �berpr�ft, ob f�r die angegebene HBCI-Version eine entsprechende
        Spezifikation verf�gbar ist. Au�erdem wird das �bergebene
        Passport �berpr�ft. Dabei werden - falls nicht vorhanden - die BPD und die UPD
        vom Kreditinstitut geholt. Bei Passports, die asymmetrische Verschl�sselungsverfahren
        benutzen (RDH), wird zus�tzlich �berpr�ft, ob alle ben�tigten Schl�ssel vorhanden
        sind. Gegebenenfalls werden diese aktualisiert.
        @param hbciversion zu benutzende HBCI-Version. g�ltige Werte sind:
               <ul>
                 <li><code>null</code> - es wird <em>die</em> HBCI-Version benutzt, die bei der
                     letzten Verwendung dieses Passports benutzt wurde</li>
                 <li>"<code>201</code>" f�r HBCI 2.01</li>
                 <li>"<code>210</code>" f�r HBCI 2.1</li>
                 <li>"<code>220</code>" f�r HBCI 2.2</li>
                 <li>"<code>plus</code>" f�r HBCI+</li>
                 <li>"<code>300</code>" f�r FinTS 3.0</li>
               </ul>
        @param passport das zu benutzende Passport. Dieses muss vorher mit
               {@link org.kapott.hbci.passport.AbstractHBCIPassport#getInstance()}
               erzeugt worden sein */
    public HBCIHandler(String hbciversion,HBCIPassport passport)
    {
        try {
            if (passport==null)
                throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_PASSPORT_NULL"));
           
            if (hbciversion==null) {
                hbciversion=passport.getHBCIVersion();
            }
            if (hbciversion.length()==0)
                throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_NO_HBCIVERSION"));

            this.kernel=new HBCIKernelImpl(this,hbciversion);
           
            this.passport=(HBCIPassportInternal)passport;
            this.passport.setParentHandlerData(this);

            registerInstitute();
            registerUser();
           
            if (!passport.getHBCIVersion().equals(hbciversion)) {
                this.passport.setHBCIVersion(hbciversion);
                this.passport.saveChanges();
            }

            dialogs=new Hashtable<String, HBCIDialog>();
        } catch (Exception e) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_CANT_CREATE_HANDLE"),e);
        }
       
        // wenn in den UPD noch keine SEPA-Informationen ueber die Konten enthalten
        // sind, versuchen wir, diese zu holen
        Properties upd=passport.getUPD();
        if (upd!=null && !upd.getProperty("_fetchedSEPA","").equals("1")) {
          // wir haben UPD, in denen aber nicht "_fetchedSEPA=1" drinsteht
          updateSEPAInfo();
        }
    }
   
    /* wenn der GV SEPAInfo unterst�tzt wird, hei�t das, dass die Bank mit
     * SEPA-Konten umgehen kann. In diesem Fall holen wir die SEPA-Informationen
     * �ber die Konten von der Bank ab - f�r jedes SEPA-f�hige Konto werden u.a.
     * BIC/IBAN geliefert */
    public void updateSEPAInfo()
    {
        Properties bpd = passport.getBPD();
        if (bpd == null)
        {
          HBCIUtils.log("have no bpd, skipping SEPA information fetching", HBCIUtils.LOG_WARN);
          return;
        }

        // jetzt noch zusaetzliche die SEPA-Informationen abholen
        try {
          if (getSupportedLowlevelJobs().getProperty("SEPAInfo")!=null) {
            HBCIUtils.log("trying to fetch SEPA information from institute", HBCIUtils.LOG_INFO);
           
            // HKSPA wird unterstuetzt
            HBCIJob sepainfo=newJob("SEPAInfo");
            sepainfo.addToQueue();
            HBCIExecStatus status=execute();
            if (status.isOK()) {
              HBCIUtils.log("successfully fetched information about SEPA accounts from institute", HBCIUtils.LOG_INFO);
             
              passport.getUPD().setProperty("_fetchedSEPA","1");
              passport.saveChanges();
            } else {
              HBCIUtils.log("error while fetching information about SEPA accounts from institute:", HBCIUtils.LOG_ERR);
              HBCIUtils.log(status.toString(), HBCIUtils.LOG_ERR);
            }
            /* beim execute() werden die Job-Result-Objekte automatisch
             * gefuellt. Der GV-Klasse fuer SEPAInfo haengt sich in diese
             * Logik rein, um gleich die UPD mit den SEPA-Konto-Daten
             * zu aktualisieren, so dass an dieser Stelle die UPD um
             * die SEPA-Informationen erweitert wurden.
             */
          } else {
            HBCIUtils.log("institute does not support SEPA accounts, so we skip fetching information about SEPA", HBCIUtils.LOG_DEBUG);
          }
        }
        catch (HBCI_Exception he)
        {
          throw he;
        }
        catch (Exception e)
        {
          throw new HBCI_Exception(e);
        }
    }
   
    private void registerInstitute()
    {
        try {
            HBCIUtils.log("registering institute",HBCIUtils.LOG_DEBUG);
            HBCIInstitute inst=new HBCIInstitute(kernel,passport,false);
            inst.register();
        } catch (Exception ex) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_CANT_REG_INST"),ex);
        }
    }

    private void registerUser()
    {
        try {
            HBCIUtils.log("registering user",HBCIUtils.LOG_DEBUG);
            HBCIUser user=new HBCIUser(kernel,passport,false);
            user.register();
        } catch (Exception ex) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_CANT_REG_USER"),ex);
        }
    }

    /** <p>Schlie�en des Handlers. Diese Methode sollte immer dann aufgerufen werden,
        wenn die entsprechende HBCI-Verbindung nicht mehr ben�tigt wird. </p><p>
        Beim Schlie�en des Handlers wird das Passport ebenfalls geschlossen.
        Sowohl das Passport-Objekt als auch das Handler-Objekt k�nnen anschlie�end
        nicht mehr benutzt werden.</p> */
    public void close()
    {
        if (passport!=null) {
            try {
                passport.close();
            } catch (Exception e) {
                HBCIUtils.log(e);
            }
        }
       
        passport=null;
        kernel=null;
        dialogs=null;
    }
   
    /* gibt die zu verwendende Customer-Id zur�ck. Wenn keine angegeben wurde
     * (customerId==null), dann wird die derzeitige passport-customerid
     * verwendet */
    private String fixUnspecifiedCustomerId(String customerId)
    {
        if (customerId==null) {
            customerId=passport.getCustomerId();
            HBCIUtils.log("using default customerid "+customerId,HBCIUtils.LOG_DEBUG);
        }
        return customerId;
    }
   
    /* gibt ein Dialog-Objekt f�r eine bestimmte Kunden-ID zur�ck. Existiert f�r
     * die Kunden-ID noch kein Dialog-Objekt, so wird eines erzeugt */
    private HBCIDialog getDialogFor(String customerId)
    {
        HBCIDialog dialog=dialogs.get(customerId);
        if (dialog==null) {
            HBCIUtils.log("have to create new dialog for customerid "+customerId,HBCIUtils.LOG_DEBUG);
            dialog=new HBCIDialog(this);
            dialogs.put(customerId,dialog);
        }
       
        return dialog;
    }

    /** <p>Beginn einer neuen HBCI-Nachricht innerhalb eines Dialoges festlegen.
        Normalerweise muss diese Methode niemals manuell aufgerufen zu werden!</p>
        <p>Mit dieser Methode wird der HBCI-Kernel gezwungen, eine neue HBCI-Nachricht
        anzulegen, in die alle nachfolgenden Gesch�ftsvorf�lle aufgenommen werden.
        Die <code>customerId</code> legt fest, f�r welchen Dialog die neue Nachricht
        erzeugt werden soll. F�r eine genauere Beschreibung von Dialogen und
        <code>customerid</code>s siehe {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)}. </p>
        @param customerId die Kunden-ID, f�r deren Dialog eine neue Nachricht
        begonnen werden soll */
    public void newMsg(String customerId)
    {
        HBCIUtils.log("have to create new message for dialog for customer "+customerId,HBCIUtils.LOG_DEBUG);
        getDialogFor(fixUnspecifiedCustomerId(customerId)).newMsg();
    }
   
    /** Erzwingen einer neuen Nachricht im Dialog f�r die aktuelle Kunden-ID.
        Diese Methode arbeitet analog zu {@link #newMsg(String)}, nur dass hier
        die <code>customerid</code> mit der Kunden-ID vorbelegt ist, wie sie
        im aktuellen Passport gespeichert ist. Siehe dazu auch
        {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)}.*/
    public void newMsg()
    {
        newMsg(null);
    }
   
    /** <p>Erzeugen eines neuen Highlevel-HBCI-Jobs. Diese Methode gibt ein neues Job-Objekt zur�ck. Dieses
        Objekt wird allerdings noch <em>nicht</em> zum HBCI-Dialog hinzugef�gt. Statt dessen
        m�ssen erst alle zur Beschreibung des jeweiligen Jobs ben�tigten Parameter mit
        {@link org.kapott.hbci.GV.HBCIJob#setParam(String,String)} gesetzt werden.
        Anschlie�end kann der Job mit {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)} zum
        HBCI-Dialog hinzugef�gt werden.</p>
        <p>Eine Beschreibung aller unterst�tzten Gesch�ftsvorf�lle befindet sich
        im Package <code>org.kapott.hbci.GV</code>.</p>
        @param jobname der Name des Jobs, der erzeugt werden soll. G�ltige
               Job-Namen sowie die ben�tigten Parameter sind in der Beschreibung des Packages
               <code>org.kapott.hbci.GV</code> zu finden.
        @return ein Job-Objekt, f�r das die entsprechenden Job-Parameter gesetzt werden m�ssen und
                welches anschlie�end zum HBCI-Dialog hinzugef�gt werden kann. */
    public HBCIJob newJob(String jobname)
    {
        HBCIUtils.log("creating new job "+jobname,HBCIUtils.LOG_DEBUG);
       
        if (jobname==null || jobname.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));
       
        HBCIJobImpl ret=null;
        String      className="org.kapott.hbci.GV.GV"+jobname;

        try {
            Class cl=Class.forName(className);
            Constructor cons=cl.getConstructor(new Class[] {HBCIHandler.class});
            ret=(HBCIJobImpl)cons.newInstance(new Object[] {this});
        } catch (ClassNotFoundException e) {
            throw new InvalidUserDataException("*** there is no highlevel job named "+jobname+" - need class "+className);
        } catch (Exception e) {
            String msg=HBCIUtilsInternal.getLocMsg("EXCMSG_JOB_CREATE_ERR",jobname);
            if (!HBCIUtilsInternal.ignoreError(null,"client.errors.ignoreCreateJobErrors",msg))
                throw new HBCI_Exception(msg,e);
        }
       
        return ret;
    }
   
    /** Erzeugt ein neues Lowlevel-Job-Objekt. F�r eine Beschreibung des Unterschiedes
        zwischen High- und Lowlevel-Definition von Jobs siehe Package <code>org.kapott.hbci.GV</code>.
        @param gvname der Lowlevel-Name des zu erzeugenden Jobs
        @return ein neues Job-Objekt, f�r das erst alle ben�tigten Lowlevel-Parameter gesetzt
                werden m�ssen und das anschlie�end zum HBCI-Dialog hinzugef�gt werden kann */
    public HBCIJob newLowlevelJob(String gvname)
    {
        HBCIUtils.log("generating new lowlevel-job "+gvname,HBCIUtils.LOG_DEBUG);

        if (gvname==null || gvname.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));

        HBCIJobImpl ret=new GVTemplate(gvname,this);
        return ret;
    }
   
    /** Do NOT use! Use {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)} instead */
    public void addJobToDialog(String customerId,HBCIJob job)
    {
        // TODO: nach dem neuen Objekt-Graph kennt der HBCIJob bereits "seinen"
        // HBCIHandler, so dass ein HBCIHandler.addJob(job) eigentlich
        // redundant ist und durch HBCIJob.addToQueue() ersetzt werden
        // k�nnte. Deswegen muss es hier einen �berpr�fung geben, ob
        // (job.getHBCIHandler() === this) ist.
       
        customerId=fixUnspecifiedCustomerId(customerId);
       
        HBCIDialog dialog=null;
        try {
            dialog=getDialogFor(customerId);
            dialog.addTask((HBCIJobImpl)job);
        } finally {
            // wenn beim hinzuf�gen des jobs ein fehler auftrat, und wenn der
            // entsprechende dialog extra f�r diesen fehlerhaften job erzeugt
            // wurde, dann kann der (leere) dialog auch wieder aus der liste
            // auszuf�hrender dialoge entfernt werden
           
            if (dialog!=null) {
                if (dialog.getAllTasks().size()==0) {
                    HBCIUtils.log("removing empty dialog for customerid "+customerId+" from list of dialogs",HBCIUtils.LOG_DEBUG);
                    dialogs.remove(customerId);
                }
            }
        }
    }

    /** @deprecated use {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String) HBCIJob.addToQueue(String)} instead */
    public void addJob(String customerId,HBCIJob job)
    {
        addJobToDialog(customerId,job);
    }
   
    /** @deprecated use {@link org.kapott.hbci.GV.HBCIJob#addToQueue() HBCIJob.addToQueue()} instead */
    public void addJob(HBCIJob job)
    {
        addJob(null,job);
    }

    /** Erzeugen eines leeren HBCI-Dialoges. <p>Im Normalfall werden HBCI-Dialoge
     * automatisch erzeugt, wenn Gesch�ftsvorf�lle mit der Methode {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)}
     * zur Liste der auszuf�hrenden Jobs hinzugef�gt werden. <code>createEmptyDialog()</code>
     * kann explizit aufgerufen werden, wenn ein Dialog erzeugt werden soll,
     * der keine Gesch�ftsvorf�lle enth�lt, also nur aus Dialog-Initialisierung
     * und Dialog-Ende besteht.</p>
     * <p>Ist die angegebene <code>customerId=null</code>, so wird der Dialog
     * f�r die aktuell im Passport gespeicherte Customer-ID erzeugt.</p>
     *
     * @param customerId die Kunden-ID, f�r die der Dialog erzeugt werden soll.
     */
    public void createEmptyDialog(String customerId)
    {
        customerId=fixUnspecifiedCustomerId(customerId);
        HBCIUtils.log("creating empty dialog for customerid "+customerId,HBCIUtils.LOG_DEBUG);
        getDialogFor(customerId);
    }
   
    /** Entspricht {@link #createEmptyDialog(String) createEmptyDialog(null)} */
    public void createEmptyDialog()
    {
        createEmptyDialog(null);
    }
   
    /** <p>Ausf�hren aller bisher erzeugten Auftr�ge. Diese Methode veranlasst den HBCI-Kernel,
        die Auftr�ge, die durch die Aufrufe der Methode
        {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)}
        zur Auftragsliste hinzugef�gt wurden, auszuf�hren. </p>
        <p>Beim Hinzuf�gen der Auftr�ge zur Auftragsqueue (mit {@link org.kapott.hbci.GV.HBCIJob#addToQueue()}
        oder {@link org.kapott.hbci.GV.HBCIJob#addToQueue(String)}) wird implizit oder explizit
        eine Kunden-ID mit angegeben, unter der der jeweilige Auftrag ausgef�hrt werden soll.
        In den meisten F�llen hat ein Benutzer nur eine einzige Kunden-ID, so dass die
        Angabe entfallen kann, es wird dann automatisch die richtige verwendet. Werden aber
        mehrere Auftr�ge via <code>addToQueue()</code> zur Auftragsqueue hinzugef�gt, und sind
        diese Auftr�ge unter teilweise unterschiedlichen Kunden-IDs auszuf�hren, dann wird
        f�r jede verwendete Kunden-ID ein separater HBCI-Dialog erzeugt und ausgef�hrt.
        Das �u�ert sich dann also darin, dass beim Aufrufen der Methode {@link #execute()}
        u.U. mehrere HBCI-Dialog mit der Bank gef�hrt werden, und zwar je einer f�r jede Kunden-ID,
        f�r die wenigstens ein Auftrag existiert. Innerhalb eines HBCI-Dialoges werden alle
        auszuf�hrenden Auftr�ge in m�glichst wenige HBCI-Nachrichten verpackt.</p>
        <p>Dazu wird eine Reihe von HBCI-Nachrichten mit dem HBCI-Server der Bank ausgetauscht. Die
        Menge der dazu verwendeten HBCI-Nachrichten kann dabei nur bedingt beeinflusst werden, da <em>HBCI4Java</em>
        u.U. selbstst�ndig Nachrichten erzeugt, u.a. wenn ein Auftrag nicht mehr mit in eine Nachricht
        aufgenommen werden konnte, oder wenn eine Antwortnachricht nicht alle verf�gbaren Daten
        zur�ckgegeben hat, so dass <em>HBCI4Java</em> mit einer oder mehreren weiteren Nachrichten den Rest
        der Daten abholt. </p>
        <p>Nach dem Nachrichtenaustausch wird ein Status-Objekt zur�ckgegeben,
        welches zur Auswertung aller ausgef�hrten Dialoge benutzt werden kann.</p>
        @return ein Status-Objekt, anhand dessen der Erfolg oder das Fehlschlagen
                der Dialoge festgestellt werden kann. */
    public HBCIExecStatus execute()
    {
        String origCustomerId=passport.getCustomerId();
        try {
            HBCIExecStatus ret=new HBCIExecStatus();
           
            while (!dialogs.isEmpty()) {
                String customerid=dialogs.keySet().iterator().next();
                HBCIUtils.log("executing dialog for customerid "+customerid,HBCIUtils.LOG_INFO);
                passport.setCustomerId(customerid);
               
                try {
                    HBCIDialog dialog=getDialogFor(customerid);
                    HBCIDialogStatus dialogStatus=dialog.doIt();
                    ret.addDialogStatus(customerid,dialogStatus);
                } catch (Exception e) {
                    ret.addException(customerid,e);
                } finally {
                    dialogs.remove(customerid);
                }
            }
            return ret;
        } finally {
            reset();
            passport.setCustomerId(origCustomerId);
            try {
                passport.closeComm();
            } catch (Exception e) {
                HBCIUtils.log("nested exception while closing passport: ", HBCIUtils.LOG_ERR);
                HBCIUtils.log(e);
            }
        }
    }
   
    /** <p>Entspricht {@link #execute()}, allerdings k�nnen Callbacks hier auch synchron
     * behandelt werden. Bei einem Aufruf von <code>executeThreaded()</code>
     * anstelle von <code>execute()</code> wird der eigentliche HBCI-Dialog in einem
     * separaten Thread gef�hrt. Bei evtl. auftretenden Callbacks wird gepr�ft,
     * ob diese synchron oder asynchron zu behandeln sind. Im asynchronen Fall
     * wird der Callback wie gewohnt durch Aufruf der <code>callback()</code>-Methode
     * des registrierten "normalen" Callback-Objektes behandelt. Soll ein Callback
     * synchron behandelt werden, terminiert diese Methode.</p>
     * <p>Das zur�ckgegebene Status-Objekt zeigt an, ob diese Methode terminierte,
     * weil ein synchron zu behandelnder Callback aufgetreten ist oder weil die
     * Ausf�hrung aller HBCI-Dialoge abgeschlossen ist.</p>
     * <p>Mehr Informationen dazu in der Datei <code>README.ThreadedCallbacks</code>.</p>*/
    public HBCIExecThreadedStatus executeThreaded()
    {
        HBCIUtils.log("main thread: starting new threaded execute",HBCIUtils.LOG_DEBUG);
       
        final ThreadSyncer sync_main=new ThreadSyncer("sync_main");
        passport.setPersistentData("thread_syncer_main",sync_main);
       
        new Thread() { public void run() {
            try {
                HBCIUtils.log("hbci thread: starting execute()",HBCIUtils.LOG_DEBUG);
               
                HBCIExecStatus execStatus=execute();
                sync_main.setData("execStatus",execStatus);
            } catch (Exception e) {
                // im fehlerfall (der eigentlich nie auftreten sollte, weil execute()
                // selbst alle exceptions catcht) muss sicherheitshalber ein noch
                // im sync-objekt enthaltenes altes execStatus-objekt entfernt
                // werden
                sync_main.setData("execStatus",null);
            } finally {
                // die existenz von "thread_syncer" im passport entscheidet
                // in CallbackThreaded dar�ber, ob der threaded callback mechanimus
                // verwendet werden soll oder das standard-callback.
                // der threaded mechanismus wird allerdings *nur* f�r hbci.execute()
                // verwendet, deshalb muss das thread_syncer-Objekt wieder entfernt
                // werden, wenn hbci.execute() beendet ist.
                passport.setPersistentData("thread_syncer_main",null);
               
                // egal, wie der hbci-thread beendet wird (fehlerhaft oder nicht),
                // am ende muss auf jeden fall ein evtl. noch wartender main-thread
                // wieder aufgeweckt werden (das kann entweder executeThreaded()
                // oder continueThreaded() sein)
                HBCIUtils.log("hbci thread: awaking main thread with hbci result data",HBCIUtils.LOG_DEBUG);
                sync_main.setData("callbackData",null);
                sync_main.stopWaiting();
               
                HBCIUtils.log("hbci thread: thread finished",HBCIUtils.LOG_DEBUG);
            }
        }}.start();
       
        // f�r dieses wait() brauche ich kein timeout, weil der hbci-thread auf
        // jeden fall ein notify() macht, sobald er beendet wird oder sobald der
        // hbci-thread callback-daten braucht. die sichere beendigung des
        // hbci-threads wiederum wird dadurch abgesichert, dass die waits() aus
        // dem hbci-thread (warten auf callback-daten) mit timeouts versehen sind
        HBCIUtils.log("main thread: waiting for hbci result or callback data from hbci thread",HBCIUtils.LOG_DEBUG);
        sync_main.startWaiting(Integer.parseInt(HBCIUtils.getParam("kernel.threaded.maxwaittime","300")), "no response from hbci thread - timeout");
       
        HBCIExecThreadedStatus threadStatus=new HBCIExecThreadedStatus();
        threadStatus.setCallbackData((Hashtable<String, Object>)sync_main.getData("callbackData"));
        threadStatus.setExecStatus((HBCIExecStatus)sync_main.getData("execStatus"));
       
        HBCIUtils.log(
            "main thread: received answer from hbci thread, returning status "+
            "(isCallback="+threadStatus.isCallback()+
            ", isFinished="+threadStatus.isFinished()+")",
            HBCIUtils.LOG_DEBUG);

        return threadStatus;
    }
   
    /** <p>Setzt bei Verwendung des threaded-callback-Mechanismus einen noch
     * aktiven HBCI-Dialog fort. Trat bei der Ausf�hrung eines HBCI-Dialoges
     * via {@link #executeThreaded()} ein synchroner Callback auf, so dass
     * <code>executeThreaded()</code> terminierte und der R�ckgabewert anzeigte,
     * dass Callback-Daten ben�tigt werden
     * ({@link HBCIExecThreadedStatus#isCallback()}<code>==true</code>), dann
     * m�ssen die ben�tigten Callback-Daten mit
     * <code>continueThreaded(String)</code> an den HBCI-Kernel �bergeben
     * werden.</p>
     * <p>Das f�hrt dazu, dass der HBCI-Kernel die �bergebenen Callback-Daten
     * an den wartenden HBCI-Thread �bergibt (der immer noch mit der Ausf�hrung
     * des HBCI-Dialoges besch�ftigt ist und auf Daten von der Anwendung
     * wartet).</p>
     * <p>Der R�ckgabewert von <code>continueThreaded(String)</code> ist wieder
     * ein <code>HBCIExecThreadedStatus</code>-Objekt (analog zu
     * <code>executeThreaded()</code>), welches anzeigt, ob weitere Callback-
     * Daten ben�tigt werden oder ob der HBCI-Dialog nun beendet ist. Falls
     * weitere Callback-Daten ben�tigt werden, sind diese wiederum via
     * <code>continueThreaded(String)</code> an den HBCI-Kernel zu �bergeben,
     * und zwar so lange, bis der HBCI-Dialog tats�chlich beendet ist.</p>
     * <p>Mehr Informationen zu threaded callbacks in der Datei
     * <code>README.ThreadedCallbacks</code>. */
    public HBCIExecThreadedStatus continueThreaded(String retData)
    {
        HBCIUtils.log("main thread: continuing hbci dialog with callback retData",HBCIUtils.LOG_DEBUG);
       
        // diese sync-objekte gibt es immer (bei richtiger verwendung des API),
        // weil continueThreaded() nur nach einem initialen executeThreaded()
        // ausgef�hrt werden darf und auch nur dann, wenn bei beiden methoden
        // noch kein endg�ltiges hbci-exec-status zur�ckgegeben wurde

        // damit wird das wait() im threaded callback wieder aufgeweckt
        ThreadSyncer sync_hbci=(ThreadSyncer)passport.getPersistentData("thread_syncer_hbci");
        sync_hbci.setData("retData",retData);
       
        HBCIUtils.log("main thread: awaking hbci thread with callback data from application",HBCIUtils.LOG_DEBUG);
        sync_hbci.stopWaiting();
       
        // f�r dieses wait() brauche ich kein timeout, weil der hbci-thread auf
        // jeden fall ein notify() macht, sobald er beendet wird oder sobald der
        // hbci-thread callback-daten braucht. die sichere beendigung des
        // hbci-threads wiederum wird dadurch abgesichert, dass die waits() aus
        // dem hbci-thread (warten auf callback-daten) mit timeouts versehen sind
        ThreadSyncer sync_main=(ThreadSyncer)passport.getPersistentData("thread_syncer_main");
        HBCIUtils.log("main thread: waiting for hbci result or new callback data from hbci thread",HBCIUtils.LOG_DEBUG);
        sync_main.startWaiting(Integer.parseInt(HBCIUtils.getParam("kernel.threaded.maxwaittime","300")), "no response from hbci thread - timeout");
       
        HBCIExecThreadedStatus threadStatus=new HBCIExecThreadedStatus();
        threadStatus.setCallbackData((Hashtable<String, Object>)sync_main.getData("callbackData"));
        threadStatus.setExecStatus((HBCIExecStatus)sync_main.getData("execStatus"));
       
        HBCIUtils.log(
            "main thread: received answer from hbci thread, returning status "+
            "(isCallback="+threadStatus.isCallback()+
            ", isFinished="+threadStatus.isFinished()+")",
            HBCIUtils.LOG_DEBUG);

        return threadStatus;
    }
   
    /** <p>Sperren der Nutzerschl�ssel. Das ist nur dann sinnvoll, wenn zwei Bedinungen erf�llt sind:</p>
        <ol>
          <li>Das verwendete Passport erlaubt die Sperrung der Schl�ssel des Nutzers (nur RDH)</li>
          <li>Im verwendeten Passport sind auch tats�chlich bereits Nutzerschl�ssel hinterlegt.</li>
        </ol>
        <p>Ist mindestens eine der beiden Bedingungen nicht erf�llt, so wird diese Methode mit einer
        Exception abgebrochen.</p>
        <p>Nach dem erfolgreichen Aufruf dieser Methode muss dieses HBCIHandler-Objekt mit
        {@link #close()} geschlossen werden. Anschlie�end muss mit dem gleichen Passport-Objekt
        ein neues HBCIHandler-Objekt angelegt werden, damit das Passport neu initialisiert wird. Bei
        dieser Neu-Initialisierung werden neue Nutzerschl�ssel f�r das Passport generiert.
<pre>
// ...
hbciHandle.lockKeys();
hbciHandle.close();

hbciHandle=new HBCIHandle(hbciversion,passport);
// ...
</pre>
        Um die Nutzerschl�ssel eines Passport nur zu <em>�ndern</em>, kann die Methode
        {@link #setKeys(java.security.KeyPair,java.security.KeyPair)}
        oder {@link #newKeys()} aufgerufen werden.</p>
        <p>Ab Version 2.4.0 von <em>HBCI4Java</em> muss der HBCIHandler nach dem
        Schl�sselsperren nicht mehr geschlossen werden. Statt dessen k�nnen direkt
        nach der Schl�sselsperrung neue Schl�ssel erzeugt oder manuell gesetzt
        werden (mit den Methoden {@link #setKeys(java.security.KeyPair,java.security.KeyPair)}
        bzw. {@link #newKeys()}. </p>
        <p>In jedem Fall muss f�r die neuen Schl�ssel, die nach einer Schl�sselsperrung
        erzeugt werden, ein neuer INI-Brief generiert und an die Bank versandt werden.</p>*/
    public void lockKeys()
    {
        // TODO: die methode hat hier eigentlich nichts zu suchen
        try {
            new HBCIUser(kernel,passport,false).lockKeys();
        } catch (Exception ex) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_LOCKFAILED"),ex);
        }
    }
   
    /** <p>Erzeugen neuer kryptografischer Schl�ssel f�r den Nutzer.
        Mit dieser Methode wird f�r den Nutzer sowohl ein neues Signier- als auch ein
        neues Chiffrierschl�sselpaar erzeugt. Die neuen Schl�sseldaten werden anschlie�end
        automatisch an die Bank �bermittelt. Sofern diese Aktion erfolgreich verl�uft,
        werden die neuen Schl�ssel in der Passport-Datei (Schl�sseldatei) gespeichert.</p>
        <p><b>ACHTUNG!</b> Vor dieser Aktion sollte unbedingt ein Backup der aktuellen Schl�sseldatei
        durchgef�hrt werden. Bei ung�nstigen Konstellationen von Fehlermeldungen seitens
        des Kreditinstitutes kann es n�mlich passieren, dass die neuen Schl�ssel trotz
        eingegangener Fehlermeldung gespeichert werden, dann w�ren aber die alten (noch g�ltigen)
        Schl�ssel �berschrieben.</p>
        <p><b>ACHTUNG!</b> In noch ung�nstigeren F�llen kann es auch vorkommen, dass neue Schl�ssel
        generiert und erfolgreich an die Bank �bermittelt werden, die neuen Schl�ssel aber nicht
        in der Schl�sseldatei gespeichert werden. Das ist insofern der ung�nstigste Fall, da
        die Bank dann schon die neuen Schl�ssel kennt, in der Passport-Datei aber noch die
        alten Schl�ssel enthalten sind und die soeben generierten neuen Schl�ssel "aus Versehen"
        weggeworfen wurden.</p> */
    public void newKeys()
    {
        // TODO: diese methode verschieben
        try {
            new HBCIUser(kernel,passport,false).generateNewKeys();
        } catch (Exception ex) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_GENKEYS_ERR"),ex);
        }
    }
   
    /** <p>Setzen der Nutzerschl�ssel auf vorgegebene Daten.
        Mit dieser Methode wird f�r den Nutzer sowohl ein neues Signier- als auch ein
        neues Chiffrierschl�sselpaar gesetzt. Die neuen Schl�sseldaten werden anschlie�end
        automatisch an die Bank �bermittelt. Sofern diese Aktion erfolgreich verl�uft,
        werden die neuen Schl�ssel in der Passport-Datei (Schl�sseldatei) gespeichert.</p>
        <p><b>ACHTUNG!</b> Vor dieser Aktion sollte unbedingt ein Backup der aktuellen Schl�sseldatei
        durchgef�hrt werden. Bei ung�nstigen Konstellationen von Fehlermeldungen seitens
        des Kreditinstitutes kann es n�mlich passieren, dass die neuen Schl�ssel trotz
        eingegangener Fehlermeldung gespeichert werden, dann w�ren aber die alten (noch g�ltigen)
        Schl�ssel �berschrieben.</p> */
    // TODO: hier digisig keys mit unterst�tzen
    public void setKeys(KeyPair sigKey,KeyPair encKey)
    {
        // TODO: diese methode verschieben
        try {
            new HBCIUser(kernel,passport,false).manuallySetNewKeys(sigKey,encKey);
        } catch (Exception ex) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_SETKEYS_ERR"),ex);
        }
    }
   
    /** Key-Management: �berpr�fen einer TAN (nur f�r PinTan-Passports!). Durch
     * den Aufruf dieser Methode wird ein "leerer" HBCI-Dialog (also ein
     * HBCI-Dialog, der nur aus Dialog-Initialisierung und Dialog-Ende besteht)
     * gestartet. Im Verlauf dieses Dialoges wird �ber den Callback-Mechanismus
     * nach einer TAN gefragt. Diese TAN wird serverseitig auf G�ltigkeit
     * �berpr�ft, die Status-Information im R�ckgabewert dieser Methode
     * enthalten entsprechende Infos �ber das Ergebnis dieser �berpr�fung.
     * @param customerId Kunden-ID, f�r die der Dialog ausgef�hrt werden soll
     *                   (<code>null</code> f�r aktuelle Kunden-ID)
     * @return ein Status-Objekt, anhand dessen der Erfolg oder das Fehlschlagen
     *         der TAN-�berpr�fung festgestellt werden kann. */
    public HBCIExecStatus verifyTAN(String customerId)
    {
        // TODO diese methode ist eine key-management-methode, muss also sp�ter
        // ins passport-objekt verschoben werden
        reset();
        createEmptyDialog(customerId);
        ((AbstractPinTanPassport)passport).activateTANVerifyMode();
        return execute();
    }
   
    /** Entspricht {@link #verifyTAN(String) verifyTAN(null)}. */
    public HBCIExecStatus verifyTAN()
    {
        return verifyTAN(null);
    }

    /** Zur�cksetzen des Handlers auf den Ausgangszustand. Diese Methode kann
     aufgerufen werden, wenn alle bisher hinzugef�gten Nachrichten und
     Auftr�ge wieder entfernt werden sollen. Nach dem Ausf�hren eines
     Dialoges mit {@link #execute()} wird diese Methode
     automatisch aufgerufen. */
    public void reset()
    {
        dialogs.clear();
    }
   
    /** Gibt das Passport zur�ck, welches in diesem Handle benutzt wird.
        @return Passport-Objekt, mit dem dieses Handle erzeugt wurde */
    public HBCIPassport getPassport()
    {
        return passport;
    }
   
    /** Gibt das HBCI-Kernel-Objekt zur�ck, welches von diesem HBCI-Handler
     * benutzt wird. Das HBCI-Kernel-Objekt kann u.a. benutzt werden, um
     * alle f�r die aktuellen HBCI-Version (siehe {@link #getHBCIVersion()})
     * implementierten Gesch�ftsvorf�lle abzufragen.
     * @return HBCI-Kernel-Objekt, mit dem der HBCI-Handler arbeitet */
    public HBCIKernel getKernel()
    {
        return kernel;
    }
   
    public MsgGen getMsgGen()
    {
        return kernel.getMsgGen();
    }
   
    /** Gibt die HBCI-Versionsnummer zur�ck, f�r die der aktuelle HBCIHandler
     * konfiguriert ist.
     * @return HBCI-Versionsnummer, mit welcher dieses Handler-Objekt arbeitet */
    public String getHBCIVersion()
    {
        return kernel.getHBCIVersion();
    }
   
    /** <p>Gibt die Namen aller vom aktuellen HBCI-Zugang (d.h. Passport)
     * unterst�tzten Lowlevel-Jobs zur�ck. Alle hier zur�ckgegebenen Job-Namen
     * k�nnen als Argument beim Aufruf der Methode
     * {@link #newLowlevelJob(String)} benutzt werden.</p>
     * <p>In dem zur�ckgegebenen Properties-Objekt enth�lt jeder Eintrag als
     * Key den Lowlevel-Job-Namen; als Value wird die Versionsnummer des
     * jeweiligen Gesch�ftsvorfalls angegeben, die von <em>HBCI4Java</em> mit dem
     * aktuellen Passport und der aktuell eingestellten HBCI-Version
     * benutzt werden wird.</p>
     * <p><em>(Prinzipiell unterst�tzt <em>HBCI4Java</em> f�r jeden
     * Gesch�ftsvorfall mehrere GV-Versionen. Auch eine Bank bietet i.d.R. f�r
     * jeden GV mehrere Versionen an. Wird mit <em>HBCI4Java</em> ein HBCI-Job
     * erzeugt, so verwendet <em>HBCI4Java</em> immer automatisch die h�chste
     * von der Bank unterst�tzte GV-Versionsnummer. Diese Information ist
     * f�r den Anwendungsentwickler kaum von Bedeutung und dient haupts�chlich
     * zu Debugging-Zwecken.)</em></p>
     * <p>Zum Unterschied zwischen High- und Lowlevel-Jobs siehe die
     * Beschreibung im Package <code>org.kapott.hbci.GV</code>.</p>
     * @return Sammlung aller vom aktuellen Passport unterst�tzten HBCI-
     * Gesch�ftsvorfallnamen (Lowlevel) mit der jeweils von <em>HBCI4Java</em>
     * verwendeten GV-Versionsnummer.*/
    public Properties getSupportedLowlevelJobs()
    {
        Hashtable<String, List<String>>  allValidJobNames=kernel.getAllLowlevelJobs();
        Properties paramSegments=passport.getParamSegmentNames();
        Properties result=new Properties();
       
        for (Enumeration e=paramSegments.propertyNames();e.hasMoreElements();) {
            String segName=(String)e.nextElement();
           
            // �berpr�fen, ob parameter-segment tats�chlich zu einem GV geh�rt
            // gilt z.b. f�r "PinTan" nicht
            if (allValidJobNames.containsKey(segName))
                result.put(segName,paramSegments.getProperty(segName));
        }
       
        return result;
    }
   
    /** <p>Gibt alle Parameter zur�ck, die f�r einen Lowlevel-Job gesetzt
        werden k�nnen. Wird ein Job mit {@link #newLowlevelJob(String)}
        erzeugt, so kann der gleiche <code>gvname</code> als Argument dieser
        Methode verwendet werden, um eine Liste aller Parameter zu erhalten, die
        f�r diesen Job durch Aufrufe der Methode
        {@link org.kapott.hbci.GV.HBCIJob#setParam(String,String)}
        gesetzt werden k�nnen bzw. m�ssen.</p>
        <p>Aus der zur�ckgegebenen Liste ist nicht ersichtlich, ob ein bestimmter
        Parameter optional ist oder gesetzt werden <em>muss</em>. Das kann aber
        durch Benutzen des Tools {@link org.kapott.hbci.tools.ShowLowlevelGVs}
        ermittelt werden.</p>
        <p>Jeder Eintrag der zur�ckgegebenen Liste enth�lt einen String, welcher als
        erster Parameter f�r den Aufruf von <code>HBCIJob.setParam()</code> benutzt
        werden kann - vorausgesetzt, der entsprechende Job wurde mit
        {@link #newLowlevelJob(String)} erzeugt. </p>
        <p>Diese Methode verwendet intern die Methode
        {@link HBCIKernel#getLowlevelJobParameterNames(String, String)}.
        Unterschied ist, dass diese Methode zum einen �berpr�ft, ob  der
        angegebene Lowlevel-Job �berhaupt vom aktuellen Passport unterst�tzt wird.
        Au�erdem wird automatisch die richtige Versionsnummer an
        {@link HBCIKernel#getLowlevelJobParameterNames(String, String)} �bergeben
        (n�mlich die Versionsnummer, die <em>HBCI4Java</em> auch beim Anlegen
        eines Jobs via {@link #newLowlevelJob(String)} verwenden wird).</p>
        <p>Zur Beschreibung von High- und Lowlevel-Jobs siehe auch die Dokumentation
        im Package <code>org.kapott.hbci.GV</code>.</p>
        @param gvname der Lowlevel-Jobname, f�r den eine Liste der Job-Parameter
        ermittelt werden soll
        @return eine Liste aller Parameter-Bezeichnungen, die in der Methode
        {@link org.kapott.hbci.GV.HBCIJob#setParam(String,String)}
        benutzt werden k�nnen */
    public List<String> getLowlevelJobParameterNames(String gvname)
    {
        if (gvname==null || gvname.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));
       
        String version=getSupportedLowlevelJobs().getProperty(gvname);
        if (version==null)
            throw new HBCI_Exception("*** lowlevel job "+gvname+" not supported");
       
        return kernel.getLowlevelJobParameterNames(gvname,version);
    }
   
    /** <p>Gibt eine Liste mit Strings zur�ck, welche Bezeichnungen f�r die einzelnen R�ckgabedaten
        eines Lowlevel-Jobs darstellen. Jedem {@link org.kapott.hbci.GV.HBCIJob} ist ein
        Result-Objekt zugeordnet, welches die R�ckgabedaten und Statusinformationen zu dem jeweiligen
        Job enth�lt (kann mit {@link org.kapott.hbci.GV.HBCIJob#getJobResult()}
        ermittelt werden). Bei den meisten Highlevel-Jobs handelt es sich dabei um bereits aufbereitete
        Daten (Kontoausz�ge werden z.B. nicht in dem urspr�nglichen SWIFT-Format zur�ckgegeben, sondern
        bereits als fertig geparste Buchungseintr�ge).</p>
        <p>Bei Lowlevel-Jobs gibt es diese Aufbereitung der Daten nicht. Statt dessen m�ssen die Daten
        manuell aus der Antwortnachricht extrahiert und interpretiert werden. Die einzelnen Datenelemente
        der Antwortnachricht werden in einem Properties-Objekt bereitgestellt
        ({@link org.kapott.hbci.GV_Result.HBCIJobResult#getResultData()}). Jeder Eintrag
        darin enth�lt den Namen und den Wert eines Datenelementes aus der Antwortnachricht.</p>
        <p>Die Methode <code>getLowlevelJobResultNames()</code> gibt nun alle g�ltigen Namen zur�ck,
        f�r welche in dem Result-Objekt Daten gespeichert sein k�nnen. Ob f�r ein Datenelement tats�chlich
        ein Wert in dem Result-Objekt existiert, wird damit nicht bestimmt, da einzelne Datenelemente
        optional sind.</p>
        <p>Diese Methode verwendet intern die Methode
        {@link HBCIKernel#getLowlevelJobResultNames(String, String)}.
        Unterschied ist, dass diese Methode zum einen �berpr�ft, ob  der
        angegebene Lowlevel-Job �berhaupt vom aktuellen Passport unterst�tzt wird.
        Au�erdem wird automatisch die richtige Versionsnummer an
        {@link HBCIKernel#getLowlevelJobResultNames(String, String)} �bergeben
        (n�mlich die Versionsnummer, die <em>HBCI4Java</em> auch beim Anlegen
        eines Jobs via {@link #newLowlevelJob(String)} verwenden wird).</p>
        <p>Mit dem Tool {@link org.kapott.hbci.tools.ShowLowlevelGVRs} kann offline eine
        Liste aller Job-Result-Datenelemente erzeugt werden.</p>
        <p>Zur Beschreibung von High- und Lowlevel-Jobs siehe auch die Dokumentation
        im Package <code>org.kapott.hbci.GV</code>.</p>
        @param gvname Lowlevelname des Gesch�ftsvorfalls, f�r den die Namen der R�ckgabedaten ben�tigt werden.
        @return Liste aller m�glichen Property-Keys, f�r die im Result-Objekt eines Lowlevel-Jobs
        Werte vorhanden sein k�nnten */
    public List<String> getLowlevelJobResultNames(String gvname)
    {
        if (gvname==null || gvname.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));
       
        String version=getSupportedLowlevelJobs().getProperty(gvname);
        if (version==null)
            throw new HBCI_Exception("*** lowlevel job "+gvname+" not supported");
       
        return kernel.getLowlevelJobResultNames(gvname,version);
    }
   
    /** <p>Gibt f�r einen Job alle bekannten Einschr�nkungen zur�ck, die bei
     der Ausf�hrung des jeweiligen Jobs zu beachten sind. Diese Daten werden aus den
     Bankparameterdaten des aktuellen Passports extrahiert. Sie k�nnen von einer HBCI-Anwendung
     benutzt werden, um gleich entsprechende Restriktionen bei der Eingabe von
     Gesch�ftsvorfalldaten zu erzwingen (z.B. die maximale Anzahl von Verwendungszweckzeilen,
     ob das �ndern von terminierten �berweisungen erlaubt ist usw.).</p>
     <p>Die einzelnen Eintr�ge des zur�ckgegebenen Properties-Objektes enthalten als Key die
     Bezeichnung einer Restriktion (z.B. "<code>maxusage</code>"), als Value wird der
     entsprechende Wert eingestellt. Die Bedeutung der einzelnen Restriktionen ist zur Zeit
     nur der HBCI-Spezifikation zu entnehmen. In sp�teren Programmversionen werden entsprechende
     Dokumentationen zur internen HBCI-Beschreibung hinzugef�gt, so dass daf�r eine Abfrageschnittstelle
     implementiert werden kann.</p>
     <p>I.d.R. werden mehrere Versionen eines Gesch�ftsvorfalles von der Bank
     angeboten. Diese Methode ermittelt automatisch die "richtige" Versionsnummer
     f�r die Ermittlung der GV-Restriktionen aus den BPD (und zwar die selbe,
     die <em>HBCI4Java</em> beim Erzeugen eines Jobs benutzt). </p>
     <p>Siehe dazu auch {@link HBCIJob#getJobRestrictions()}.</p>
     @param gvname Lowlevel-Name des Gesch�ftsvorfalles, f�r den die Restriktionen
     ermittelt werden sollen
     @return Properties-Objekt mit den einzelnen Restriktionen */
    public Properties getLowlevelJobRestrictions(String gvname)
    {
        if (gvname==null || gvname.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));
       
        String version=getSupportedLowlevelJobs().getProperty(gvname);
        if (version==null)
            throw new HBCI_Exception("*** lowlevel job "+gvname+" not supported");
       
        return passport.getJobRestrictions(gvname,version);
    }

    /** <p>�berpr�fen, ein bestimmter Highlevel-Job von der Bank angeboten
        wird. Diese Methode kann benutzt werden, um <em>vor</em> dem Erzeugen eines
        {@link org.kapott.hbci.GV.HBCIJob}-Objektes zu �berpr�fen, ob
        der gew�nschte Job �berhaupt von der Bank angeboten wird. Ist das
        nicht der Fall, so w�rde der Aufruf von
        {@link org.kapott.hbci.manager.HBCIHandler#newJob(String)}
        zu einer Exception f�hren.</p>
        <p>Eine Liste aller zur Zeit verf�gbaren Highlevel-Jobnamen ist in der Paketbeschreibung
        des Packages <code>org.kapott.hbci.GV</code> zu finden. Wird hier nach einem Highlevel-Jobnamen
        gefragt, der nicht in dieser Liste enthalten ist, so wird eine Exception geworfen.</p>
        <p>Mit dieser Methode k�nnen nur Highlevel-Jobs �berpr�ft werden. Zum �berpr�fen,
        ob ein bestimmter Lowlevel-Job unterst�tzt wird, ist die Methode
        {@link HBCIHandler#getSupportedLowlevelJobs()}
        zu verwenden.</p>
        @param jobnameHL der Highlevel-Name des Jobs, dessen Unterst�tzung �berpr�ft werden soll
        @return <code>true</code>, wenn dieser Job von der Bank unterst�tzt wird und
        mit <em>HBCI4Java</em> verwendet werden kann; ansonsten <code>false</code> */
    public boolean isSupported(String jobnameHL)
    {
        if (jobnameHL==null || jobnameHL.length()==0)
            throw new InvalidArgumentException(HBCIUtilsInternal.getLocMsg("EXCMSG_EMPTY_JOBNAME"));
       
        try {
            Class cl=Class.forName("org.kapott.hbci.GV.GV"+jobnameHL);
            String lowlevelName=(String)cl.getMethod("getLowlevelName",(Class[])null).invoke(null,(Object[])null);
            return getSupportedLowlevelJobs().keySet().contains(lowlevelName);
        } catch (Exception e) {
            throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_HANDLER_HLCHECKERR",jobnameHL),e);
        }
    }
   
    /** Abholen der BPD bzw. UPD erzwingen. Beim Aufruf dieser Methode wird
     * automatisch ein HBCI-Dialog ausgef�hrt, der je nach Wert von <code>selectX</code>
     * die BPD und/oder UPD erneut abholt. Alle bis zu diesem Zeitpunkt erzeugten
     * ({@link org.kapott.hbci.GV.HBCIJob#addToQueue()}) und noch nicht ausgef�hrten Jobs werden dabei
     * wieder aus der Job-Schlange entfernt.
     * @param selectX kann aus einer Kombination (Addition) der Werte
     * {@link #REFRESH_BPD} und {@link #REFRESH_UPD} bestehen
     * @return Status-Objekt, welches Informationen �ber den ausgef�hrten
     * HBCI-Dialog enth�lt */
    public HBCIDialogStatus refreshXPD(int selectX)
    {
        if ((selectX & REFRESH_BPD)!=0) {
            passport.clearBPD();
        }
        if ((selectX & REFRESH_UPD)!=0) {
            passport.clearUPD();
        }

        reset();
       
        String customerId=passport.getCustomerId();
        getDialogFor(customerId);
        HBCIDialogStatus result=execute().getDialogStatus(customerId);
        return result;
    }
}
TOP

Related Classes of org.kapott.hbci.manager.HBCIHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.