/* $Id: JobContext.java,v 1.8 2005/06/10 18:03:02 kleiner Exp $
This file is part of HBCI4Java
Copyright (C) 2001-2005 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.server;
import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.manager.HBCIUtilsInternal;
import org.kapott.hbci.status.HBCIRetVal;
import org.kapott.hbci.structures.Konto;
import org.kapott.hbci.structures.Value;
/** <p>Liefert Informationen ber einen eingegangenen Auftrag und nimmt Rckgabedaten
auf. Ein Objekt dieser Klasse wird fr jedes eingegangene Auftragssegment
einer Kundennachricht vom HBCI4Java-Server-Code erzeugt. Mit diesem
<code>JobContext</code>-Objekt wird dann der Callback-Handler
{@link ServerCallback#handleGV(JobContext)} aufgerufen, der von der
HBCI-Server-Anwendung implementiert werden muss.</p>
<p>Die <code>JobContext</code>-Klasse stellt auerdem einige Hilfsmethoden
fr die leichtere Auswertung der Auftragsdaten zur Verfgung.</p>*/
public class JobContext
{
private Dialog conn;
private String jobname;
private int jobversion;
private Properties jobData;
private ArrayList rets;
private Properties resultData;
public JobContext(Dialog conn,String jobname,int jobversion,Properties jobData)
{
this.conn=conn;
this.jobname=jobname;
this.jobversion=jobversion;
this.jobData=jobData;
this.rets=new ArrayList();
this.resultData=new Properties();
}
/** Gibt den Namen des eingegangenen Auftragssegmentes zurck. Dabei handelt
es sich um die gleichen Namen, die in einer HBCI4Java-Client-Anwendung mit
{@link org.kapott.hbci.manager.HBCIHandler#getSupportedLowlevelJobs()}
ermittelt werden knnen. Eine Liste aller mglichen Jobnamen erhlt man
mit dem Tool {@link org.kapott.hbci.tools.ShowLowlevelGVs}. Dieser
Jobname ist immer einer der Namen, die von dem implementierten
{@link org.kapott.hbci.server.datastore.DataStore}-Objekt mit der
Methode {@link org.kapott.hbci.server.datastore.DataStore#getSupportedGVs(String)}
zurckgegeben werden (das stimmt noch nicht, es werden zur Zeit auch Auftrge
akzeptiert, die gar nicht in den BPD aufgefhrt sind ***).
@return interner Name des eingegangenen Auftrages */
public String getJobName()
{
return jobname;
}
/** Gibt die Versionsnummer des eingegangenen Geschftsvorfalles zurck. Es handelt
sich dabei um eine der Versionsnummern, die via
{@link org.kapott.hbci.server.datastore.DataStore#getGVVersions(String,String)} fr
den aktuellen {@link #getJobName() Job-Namen} ermittelt werden knnen
(das stimmt noch nicht, es werden zur Zeit auch Auftrge
akzeptiert, die gar nicht in den BPD aufgefhrt sind ***).
@return Versionsnummer des Geschftsvorfall-Auftragssegmentes */
public int getJobVersion()
{
return jobversion;
}
/** Gibt ein Objekt mit den Auftragsdaten des eingegangenen Auftrages zurck.
Die fr jeden Geschftsvorfall jeweils mglichen Daten lassen sich mit dem
Tool {@link org.kapott.hbci.tools.ShowLowlevelGVs} ermitteln.
@return <code>Properties</code>-Objekt mit Auftragsdaten */
public Properties getJobData()
{
return jobData;
}
/** Ermitteln eines bestimmten Eintrages aus den eingegangen Auftragsdaten.
Ein Aufruf von <code>getJobData(key)</code> entspricht dem Aufruf von
{@link #getJobData() getJobData().getProperty(key)}.
@param key Name fr das Auftragsdatenelement, dessen Wert ermittelt werden soll
@return Wert des entsprechenden Auftragsdatenelementes */
public String getJobData(String key)
{
return jobData.getProperty(key);
}
private String getDERef(String path)
{
return getJobData("_deref."+path);
}
/** Gibt die Kunden-ID zurck, mit der der aktuelle HBCI-Dialog gefhrt wird
und fr die also der aktuelle Auftrag bearbeitet werden soll
@return aktuelle Kunden-ID */
public String getCustomerId()
{
return conn.getCustomerId();
}
/** Gibt die Nutzerkennung zurck, mit der der aktuelle HBCI-Dialog gefhrt wird
und fr die also der aktuelle Auftrag bearbeitet werden soll
@return aktuelle Benutzerkennung */
public String getUserId()
{
return conn.getUserId();
}
/** Hinzufgen eines auftragsspezifischen Rckgabewertes zur Antwortnachricht.
Diese Methode erzeugt eine HBCI-Rckmeldung, die sich automatisch auf das aktuelle
Auftragssegment bezieht. Diese Methode hat eine gewisse "Intelligenz" der
folgenden Art eingebaut: Eine Erfolgsmeldung (<code>code</code> beginnt mit
'0') wird nur dann tatschlich als Rckmeldung hinzugefgt, wenn vorher nicht
bereits eine Fehlermeldung hinzugefgt wurde. Eine hinzugefgte Fehlermeldung
(<code>code</code> beginnt mit '9') bewirkt, dass alle evtl. vorher
hinzugefgten Erfolgsmeldungen aus der Menge der Rckmeldungen entfernt
werden und dass keine weiteren Erfolgsmeldungen hinzugefgt werden knnen.
@param dename Name des Datenelements, auf das sich diese Meldung bezieht
(kann <code>null</code> sein) - fr eine sinnvolle Belegung ist die Kenntnis
der intern von <em>HBCI4Java</em> verwendeten HBCI-Spezifikation ntig
@param code Codenummer der Rckmeldung (siehe HBCI-Spezifikation)
@param text Textmeldung, die zurckgegeben werden soll
@param params Feld mit optionalen Parametern, die die Fehlermeldung nher spezifizieren */
public void addStatus(String dename,String code,String text,String[] params)
{
String deref=(dename!=null)?getDERef(dename):null;
rets.add(new HBCIRetVal(null,deref,null,code,text,params));
}
public ArrayList getStatusData()
{
return rets;
}
/** Setzen eines Datenelementes fr die zu generierende Antwortnachricht. Die Namen
(<code>key</code>) der mglichen Datenelemente je Auftragstyp knnen mit dem
Tool {@link org.kapott.hbci.tools.ShowLowlevelGVRs} ermittelt werden. Da ein
Auftrag u.U. mehrere Antwortdatenstze erzeugen kann (z.B. eine Saldenabfrage
fr alle Konten gleichzeitig), kann mit dem Parameter <code>segCounter</code>
zustzlich angegeben werden, fr den wievielten Antwortdatensatz das Datenelement
benutzt werden soll (Zhlung beginnt bei 0!).
@param segCounter Nummer des Antwortdatensatzes (beginnend bei 0), fr den dieses
Datenelement gesetzt werden soll
@param key Name des zu setzenden Antwortdatenelementes
@param value Wert, auf das Datenelement gesetzt werden soll */
public void setData(int segCounter,String key,String value)
{
resultData.setProperty(HBCIUtilsInternal.withCounter("result",segCounter)+"."+key,value);
}
public Properties getResultData()
{
return resultData;
}
/** Hilfmethode zum berprfen der Gltigkeit der Kreditinstitutskennung in einem
Auftragssegment. Diese Methode berprft, ob eine Kreditinstitutskennung
(<code><em>KIK</em></code>), welche in einem Auftragssegment bermittelt wurde,
gltig ist (d.h. <code>KIK.country</code> und <code>KIK.blz</code> entsprechen
den Daten des HBCI-Servers). Ist das nicht der Fall, so wird automatisch
eine entsprechende Fehlermeldung zur Antwortnachricht hinzugefgt.
@param header Name der KIK-Datenelementgruppe (<code>[*.]KIK</code>)
@return <code>true</code>, wenn Daten in <code>KIK</code>-Element mit den
Serverdaten bereinstimmen, sonst <code>false</code> */
public boolean checkKIK(String header)
{
String country=getJobData(header+".country");
String blz=getJobData(header+".blz");
if (!country.equals(ServerData.getInstance().getCountry()) ||
!blz.equals(ServerData.getInstance().getBLZ())) {
addStatus(header,"9210","Ungltige Kreditinstitutskennung",null);
return false;
}
return true;
}
/** Alle fr die aktuelle UserId/CustomerId verfgbaren Kontoverbindungen zurckmelden.
Diese Methode ermittelt alle Konten, auf die der Nutzer, der den aktuellen Dialog
fhrt, zugreifen darf. Dazu werden intern zunchst die fr die aktuelle
Nutzer-ID ({@link #getUserId()}) gltigen Kontoverbindungen ermittelt
({@link org.kapott.hbci.server.datastore.DataStore#getAccounts(String)}). Daraus werden
dann die Eintrge extrahiert, deren <code>.customerid</code>-Feld mit der aktuellen
Kunden-ID ({@link #getCustomerId()}) bereinstimmt. Die so ermittelte Menge von
Kontoverbindungen wird zurckgegeben.
@return Liste der Konten, auf die der aktuelle Nutzer/Kunde zugreifen darf */
public Konto[] getAllMyAccounts()
{
// alle konten fr user holen
return ServerData.getInstance().getAccounts(getUserId(),getCustomerId());
}
/** Gibt alle Konten aller Kunden zurck, die an dieser Bank gefhrt werden.
@return Feld mit allen Konten bei dieser Bank */
public Konto[] getAllAccounts()
{
// alle konten fr user holen
return ServerData.getInstance().getAllAccounts();
}
/** Hilfsmethode zum berprfen der Gltigkeit einer Kontoverbindung aus den
Auftragsdaten des aktuellen Auftrages. Diese Methode berprft, ob die
jeweilige Kontoverbindung (<code>header</code>) ein gltiges Konto fr den
aktuellen Nutzer/Kunden darstellt (siehe {@link #extractMyAccount(String)}). Ist das
der Fall, so wird das entsprechende {@link org.kapott.hbci.structures.Konto}-Objekt
zurckgegeben, sonst <code>null</code>. Falls kein passendes Nutzerkonto
gefunden werden konnte, so wird automatisch eine entsprechende Fehlermeldung
zur Antwortnachricht hinzugefgt.
@param header Name der KTV-Datenelementgruppe (<code>[*.]KTV</code>) innerhalb der
Auftragsdaten
@return <code>null</code>, wenn die Kontodaten kein gltiges Konto des aktuellen
Nutzers/Kunden darstellen, sonst das entsprechende {@link org.kapott.hbci.structures.Konto}-Objekt*/
public Konto checkKTV(String header)
{
Konto acc=extractMyAccount(header);
if (acc==null)
addStatus(header,"9210","ungltige Kontoverbindung fr aktuelle Kunden-ID",null);
return acc;
}
private Konto findAccountInList(String header,Konto[] accounts)
{
boolean ok=false;
// kontodaten aus job extrahieren
String country=getJobData(header+".KIK.country");
String blz=getJobData(header+".KIK.blz");
String number=getJobData(header+".number");
// berprfen, ob kontodaten aus request mit einem der gltigen user-konten bereinstimmt
Konto acc=null;
for (int i=0;i<accounts.length;i++) {
acc=accounts[i];
if (acc.blz.equals(blz) &&
acc.country.equals(country) &&
acc.number.equals(number)) {
// konto gefunden
ok=true;
break;
}
}
return ok?acc:null;
}
/** Extrahieren einer Kontoverbindung und Zurckgeben des entsprechenden
<code>Konto</code>-Objektes. Diese Methode gibt <code>null</code>
zurck, wenn es fr den aktuellen Nutzer/Kunden kein Konto mit der
extrahierten Kontoverbindung gibt. Ansonsten wird das <code>Konto</code>-Objekt
zurckgegeben, welches der Kontoverbindung entspricht. Es muss sich dabei
also immer um ein Konto handeln, welches dem aktuellen Nutzer/Kunden
gehrt. Zustzlich zu den Verbindungsdaten aus dem Auftragssegment
werden in dem <code>Konto</code>-Objekt weitere Informationen (wie
Kontowhrung, Name des Inhabers) usw. aus den server-internen Datenbestnden
eingetragen.
@see #getAllMyAccounts()
@param header Name der KTV-Datenelementgruppe (<code>[*.]KTV</code>) innerhalb der
Auftragsdaten
@return <code>null</code>, wenn die Kontodaten kein gltiges Konto des aktuellen
Nutzers/Kunden darstellen, sonst das entsprechende {@link org.kapott.hbci.structures.Konto}-Objekt*/
public Konto extractMyAccount(String header)
{
return findAccountInList(header,getAllMyAccounts());
}
/** Extrahieren einer Kontoverbindung und Zurckgeben eines entsprechenden
<code>Konto</code>-Objektes. Diese Methode extrahiert die blichen
Verbindungsdaten (Lndercode, Bankleitzahl, Kontonummer) und stellt ein
<code>Konto</code>-Objekt bereit, welches mit diesen Werten initialisiert
ist. Im Gegensatz zu {@link #extractMyAccount(String)} wird hier keine
berprfung vorgenommen, ob das Konto dem aktuellen Nutzer gehrt. Das
hat aber auch den Effekt, dass keine zustzlichen Kontoinformationen in
das <code>Konto</code>-Objekt eingestellt werden (wie z.B. Whrung,
Name des Inhabers usw.). Falls das referenzierte Konto jedoch bei dieser
Bank gefhrt wird (siehe {@link #getAllAccounts()}), dann werden auch
die entsprechenden zustzlichen Daten (Kunden-ID, Whrung) gesetzt.
@param header Name der KTV-Datenelementgruppe (<code>[*.]KTV</code>) innerhalb der
Auftragsdaten
@return {@link org.kapott.hbci.structures.Konto}-Objekt, welches mit den
jeweiligen Daten aus dem Auftragssegment initialisiert ist */
public Konto extractOtherAccount(String header)
{
Konto acc=findAccountInList(header,getAllAccounts());
if (acc==null) {
acc=new Konto(getJobData(header+".KIK.country"),
getJobData(header+".KIK.blz"),
getJobData(header+".number"));
}
return (acc!=null && acc.number!=null)?acc:null;
}
/** Geldbetrag aus Auftragsdaten extrahieren.
@param header Name des BTG-Datenelementes, welches extrahiert werden soll
@return <code>Value</code>-Objekt, welches den extrahierten Geldbetrag
reprsentiert */
public Value extractBTG(String header)
{
Value value=new Value(getJobData(header+".value"),getJobData(header+".curr"));
return (value.curr!=null)?value:null;
}
/** Extrahieren von evtl. mehrfach auftretenden Datenelemente. Das Datenelement
mit dem Pfad <code>header</code> wird als Datenelement betrachtet, welches
0..n mal auftreten kann. Diese Methode gibt ein <code>String[]</code>
zurck, welches alle Vorkommen dieses DE enthlt (kann zum Beispiel
fr die Extraktion von Verwendungszweckzeilen benutzt werden --
<code>header=usage.usage</code>).
@param header Pfadname des zu extrahierenden Datenelementes
@return <code>String[]</code> (evtl. mit Lnge 0) mit den entsprechenden
Daten */
public String[] extractStringArray(String header)
{
ArrayList ret=new ArrayList();
for (int i=0;;i++) {
String st=getJobData(HBCIUtilsInternal.withCounter(header,i));
if (st==null)
break;
ret.add(st);
}
return (String[])ret.toArray(new String[0]);
}
/** Extrahiert eine Datumsangabe.
@param header Pfadname des zu extrahierenden Datenelementes
@return extrahiertes Datum als Java-Objekt */
public Date extractDate(String header)
{
String st=getJobData(header);
return st!=null?HBCIUtils.string2Date(st):null;
}
}