/* $Id: MsgGen.java,v 1.1 2011/05/04 22:37:46 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.io.InputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.protocol.MSG;
import org.kapott.hbci.protocol.factory.MSGFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/* Message-Generator-Klasse. Diese Klasse verwaltet die Syntax-Spezifikation
* f�r die zu verwendende HBCI-Version. Hiermit wird das Erzeugen von
* HBCI-Nachrichten gekapselt.
* Dazu wird eine Hashtable verwaltet, die die Daten enth�lt, die in die
* jeweilige Nachricht aufgenommen werden sollen. Die Hashtable enth�lt als
* Key den "Pfad" zum Datenelement (DialogInit.MsgHead.hbciversion), als
* Value den einzustellenden Wert im Klartext.
* Das Erzeugen einer Nachricht geschieht in drei Schritten:
* 1) MsgGen.reset() -- vollst�ndiges Leeren der Daten-Hashtable
* 2) MsgGen.set(key,value) -- speichern eines Datums f�r die Nachricht
* in der Hashtable
* 3) MsgGen.generate(msgName) -- erzeugen der Nachricht mit dem Namen
* <msgName>. Dabei werden auch nur die Daten aus der Hashtable
* verwendet, dir mit "<msgName>." beginnen (so dass in der Datenhashtable
* auch zus�tzliche Daten gespeichert werden k�nnen, solange sie nicht
* mit "<msgName>." beginnen).*/
public final class MsgGen
{
private Document syntax; /**< @internal @brief The representation of the syntax used by this generator */
private Hashtable<String, String> clientValues; /**< @internal @brief A table of properties set by the user to specify the message to be generated */
// Wird vom Server-Code benutzt. Wenn ein Dialog reinkommt mit einer HBCI-
// Version, die schon mal benutzt wurde, dann wird nicht das entsprechende
// XML-Document nochmal erzeugt, sondern das alte wiederbenutzt.
public MsgGen(Document syntax)
{
this.syntax=syntax;
this.clientValues=new Hashtable<String, String>();
}
/* Initialisieren eines Message-Generators. Der <syntaFileStream> ist ein
* Stream, mit dem eine XML-Datei mit einer HBCI-Syntaxspezifikation
* eingelesen wird */
public MsgGen(InputStream syntaxFileStream)
{
try {
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
dbf.setIgnoringComments(true);
dbf.setValidating(true);
DocumentBuilder db=dbf.newDocumentBuilder();
syntax=db.parse(syntaxFileStream);
syntaxFileStream.close();
clientValues=new Hashtable<String, String>();
} catch (FactoryConfigurationError e) {
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_MSGGEN_DBFAC"),e);
} catch (ParserConfigurationException e) {
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_MSGGEN_DB"),e);
} catch (Exception e) {
throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_MSGGEN_STXFILE"),e);
}
}
/** @internal
@brief Generates the HBCI message @p msgName.
The syntax description for the message to be generated is taken from an
XML node @c MSGdef where the attribute @c id equals @p msgName.
To build the message the values stored in @c clientValues will be used.
@param msgName The name (i.e. XML-identifier for a MSGdef-node) of the message to be generated.
@return A new MSG object representing the generated message.
*/
public MSG generate(String msgName)
{
return MSGFactory.getInstance().createMSG(msgName,this,clientValues);
}
/** @internal
@brief Sets a certain property that is later used in message generation.
@param path The path to the syntax element for which the value is to be set. For
more information about paths, see
SyntaxElement::SyntaxElement()
@param value The new value for the specified element.
*/
public void set(String path, String value)
{
clientValues.put(path,value);
}
/** @internal @brief Clears the list of already set properties */
public void reset()
{
clientValues.clear();
}
/** @internal @brief Returns the representation of the HBCI syntax used by this generator
@return The internally used representation of a HBCI syntax description.
*/
public Document getSyntax()
{
return syntax;
}
public Hashtable<String, List<String>> getLowlevelGVs()
{
Hashtable<String, List<String>> result=new Hashtable<String, List<String>>();
Element gvlist=syntax.getElementById("GV");
NodeList gvs=gvlist.getChildNodes();
int len=gvs.getLength();
StringBuffer type=new StringBuffer();
for (int i=0;i<len;i++) {
Node gvref=gvs.item(i);
if (gvref.getNodeType()==Node.ELEMENT_NODE) {
type.setLength(0);
type.append(((Element)gvref).getAttribute("type"));
int pos=type.length()-1;
char ch;
while ((ch=type.charAt(pos))>='0' && ch<='9') {
pos--;
}
String gvname=type.substring(0,pos+1);
List<String> entry= result.get(gvname);
if (entry==null) {
entry=new ArrayList<String>();
result.put(gvname,entry);
}
entry.add(type.substring(pos+1));
}
}
return result;
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-parameter
* zur�ck */
public List<String> getGVParameterNames(String specname)
{
int versionPos=specname.length()-1;
char ch;
while ((ch=specname.charAt(versionPos))>='0' && ch<='9') {
versionPos--;
}
return getGVParameterNames(
specname.substring(0,versionPos+1),
specname.substring(versionPos+1));
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-parameter
* zur�ck */
public List<String> getGVParameterNames(String gvname,String version)
{
ArrayList<String> ret=new ArrayList<String>();
Element gvdef=syntax.getElementById(gvname+version);
NodeList gvcontent=gvdef.getChildNodes();
int len=gvcontent.getLength();
boolean first=true;
for (int i=0;i<len;i++) {
Node contentref=gvcontent.item(i);
if (contentref.getNodeType()==Node.ELEMENT_NODE) {
// skip seghead
if (first) {
first=false;
} else {
addLowlevelProperties(ret,"",(Element)contentref);
}
}
}
return ret;
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-result-parameter
* zur�ck */
public List<String> getGVResultNames(String specname)
{
int versionPos=specname.length()-1;
char ch;
while ((ch=specname.charAt(versionPos))>='0' && ch<='9') {
versionPos--;
}
return getGVResultNames(
specname.substring(0,versionPos+1),
specname.substring(versionPos+1));
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-result-parameter
* zur�ck */
public List<String> getGVResultNames(String gvname,String version)
{
ArrayList<String> ret=new ArrayList<String>();
Element gvdef=syntax.getElementById(gvname+"Res"+version);
if (gvdef!=null) {
NodeList gvcontent=gvdef.getChildNodes();
int len=gvcontent.getLength();
boolean first=true;
for (int i=0;i<len;i++) {
Node contentref=gvcontent.item(i);
if (contentref.getNodeType()==Node.ELEMENT_NODE) {
if (first) {
first=false;
} else {
addLowlevelProperties(ret,"",(Element)contentref);
}
}
}
}
return ret;
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-restriction-
* parameter zur�ck */
public List<String> getGVRestrictionNames(String specname)
{
int versionPos=specname.length()-1;
char ch;
while ((ch=specname.charAt(versionPos))>='0' && ch<='9') {
versionPos--;
}
return getGVRestrictionNames(
specname.substring(0,versionPos+1),
specname.substring(versionPos+1));
}
/* gibt f�r einen hbci-gv ("saldo3") die liste aller ll-job-restriction-
* parameter zur�ck */
public List<String> getGVRestrictionNames(String gvname,String version)
{
ArrayList<String> ret=new ArrayList<String>();
// SEGdef id="TermUebPar1" finden
Element gvdef=syntax.getElementById(gvname+"Par"+version);
if (gvdef!=null) {
// alle darin enthaltenen elemente durchlaufen, bis ein element
// DEG type="ParTermUeb1" gefunden ist
NodeList gvcontent=gvdef.getChildNodes();
int len=gvcontent.getLength();
for (int i=0;i<len;i++) {
Node contentref=gvcontent.item(i);
if (contentref.getNodeType()==Node.ELEMENT_NODE) {
String type=((Element)contentref).getAttribute("type");
if (type.startsWith("Par")) {
// wenn ein DEG type="ParTermUeb" gefunden ist, k�nnen
// alle umgebenenden schleifenvariablen wiederverwendet
// werden, weil es nur *ein* solches element geben kann
// und die umgebende schleife demzufolge abgebrochen werden
// kann, nachdem das gefundenen element bearbeitet wurde
// DEGdef id="ParTermUeb1" finden
gvdef=syntax.getElementById(type);
gvcontent=gvdef.getChildNodes();
len=gvcontent.getLength();
// darin alle elemente durchlaufen und deren namen
// zur ergebnisliste hinzuf�gen
for (i=0;i<len;i++) {
contentref=gvcontent.item(i);
if (contentref.getNodeType()==Node.ELEMENT_NODE) {
addLowlevelProperties(ret,"",(Element)contentref);
}
}
break;
}
}
}
}
return ret;
}
private void addLowlevelProperties(ArrayList<String> result,String path,Element ref)
{
if (ref.getAttribute("type").length()!=0) {
if (ref.getNodeName().equals("DE")) {
String name=ref.getAttribute("name");
result.add(pathWithDot(path)+name);
} else {
String name=ref.getAttribute("name");
if (name.length()==0)
name=ref.getAttribute("type");
Element def=syntax.getElementById(ref.getAttribute("type"));
NodeList defcontent=def.getChildNodes();
int len=defcontent.getLength();
for (int i=0;i<len;i++) {
Node content=defcontent.item(i);
if (content.getNodeType()==Node.ELEMENT_NODE)
addLowlevelProperties(result,pathWithDot(path)+name,(Element)content);
}
}
}
}
private static String pathWithDot(String path)
{
return (path.length()==0)?path:(path+".");
}
public String get(String key)
{
return clientValues.get(key);
}
}