Package org.kapott.hbci.protocol

Source Code of org.kapott.hbci.protocol.SyntaxElement

/*  $Id: SyntaxElement.java,v 1.1 2011/05/04 22:38:03 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.protocol;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;

import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.exceptions.NoSuchPathException;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.manager.HBCIUtilsInternal;
import org.kapott.hbci.protocol.factory.MultipleDEGsFactory;
import org.kapott.hbci.protocol.factory.MultipleDEsFactory;
import org.kapott.hbci.protocol.factory.MultipleSEGsFactory;
import org.kapott.hbci.protocol.factory.MultipleSFsFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/* ein syntaxelement ist ein strukturelement einer hbci-nachricht (die nachricht
    selbst, eine segmentfolge, ein einzelnes segment, eine deg oder
    ein einzelnes de) */
public abstract class SyntaxElement
{
    private List<MultipleSyntaxElements> childContainers;  /**< @internal @brief alle in diesem element enthaltenen unterelemente */
    private String name;   /**< @internal @brief bezeichner fuer dieses element */
    private String type;
    private String path;   /**< @internal @brief pfadname dieses elementes innerhalb einer MSG */
    private char predelim;  /**< @internal @brief nur beim parsen: zeichen, das vor diesem element stehen muesste */
    private boolean valid; /**< @internal @brief indicates if this element is really valid, i.e. will appear in
                                an outgoing hbci message resp. in returned results from an incoming message*/
   
    private MultipleSyntaxElements parent;
   
    // Wird von einigen Rewriter-Modules beim Parsen verwendet, um im Antwort-String
    // an der richtigen Stelle Daten auszuschneiden oder einzuf�gen.
    // TODO: Problem dabei ist nur: sobald auch nur *ein* Rewriter die Antwort-
    // Message ver�ndert, stimmen von allen anderen SyntaxElementen die
    // Werte f�r posInMsg nicht mehr (es sei denn, es wird nach dem
    // Ver�ndern ein neues MSG-Objekt erzeugt).
    private int posInMsg;
   
    private Document syntax;
    private Node     def;
   
    public final static boolean TRY_TO_CREATE=true;
    public final static boolean DONT_TRY_TO_CREATE=false;
    public final static boolean ALLOW_OVERWRITE=true;
    public final static boolean DONT_ALLOW_OVERWRITE=false;

    /** gibt einen string mit den typnamen (msg,seg,deg,de,...) des
     elementes zurueck */
    protected abstract String getElementTypeName();
   
    /** liefert das delimiter-zeichen zurueck, dass innerhalb dieses
     syntaxelementes benutzt wird, um die einzelnen child-elemente voneinander
     zu trennen */
    protected abstract char getInDelim();
   
    /** erzeugt einen neuen Child-Container, welcher durch den
    xml-knoten 'ref' identifiziert wird; wird beim erzeugen von elementen
    benutzt */
    protected abstract MultipleSyntaxElements createNewChildContainer(Node ref, Document syntax);
   
    // TODO: aus konsistenz-gr�nden auch in MultipleSyntaxElements create und
    // createAndAdd trennen
    /** beim parsen: haengt an die 'childElements' ein neues Element an. der
     xml-knoten 'ref' gibt an, um welches element es sich dabei handelt; aus
     'res' (der zu parsende String) wird der wert fuer das element ermittelt
     (falls es sich um ein de handelt); in 'predefined' ist der wert des
     elementes zu finden, der laut syntaxdefinition ('syntax') an dieser stelle
     auftauchen mueste (optional; z.b. fuer segmentcodes); 'predelim*' geben
     die delimiter an, die direkt vor dem zu erzeugenden syntaxelement
     auftauchen muessten */
    protected abstract MultipleSyntaxElements parseNewChildContainer(Node ref, char predelim0, char predelim1, StringBuffer res, int fullResLen, Document syntax, Hashtable<String,String> predefs,Hashtable<String,String> valids);
   
   
    /** wird fuer datenelemente benoetigt, die sonst unbeabsichtigt generiert werden koennten.
        das problem ist, dass es datenelemente (bisher nur bei segmenten bekannt) gibt,
        die aus einigen "required" unterelementen bestehen und aus einigen optionalen
        unterelementen. wenn *alle* "required" elemente bereits durch predefined values
        bzw. durch automatisch generierte werte vorgegeben sind, dann wird das entsprechende
        element erzeugt, da es auch ohne angabe der optionalen unterelemente gueltig ist.
       
        es ist aber u.U. gar nicht beabsichtigt, dass dieses element erzeugt wird (beispiel
        segment "KIOffer", wo nur die DEG SegHead required ist, alle anderen elemente sind
        optional). es kann also vorkommen, dass ein element *unbeabsichtigt* nur aus den
        vorgabedaten erzeugt wird.

        bei den elementen, bei denen das passieren kann, wird in der xml-spezifikation
        deshalb zusaetzlich das attribut "needsRequestTag" angegeben. der wert dieses
        attributes wird hier in der variablen @p needsRequestTag gespeichert.

        beim ueberpruefen, ob das aktuelle element gueltig ist (mittels @c validate() ),
        wird neben der gueltigkeit aller unterelemente zusaetzlich ueberprueft, ob dieses
        element ein request-tag benoetigt, und wenn ja, ob es vorhanden ist. wenn die
        @p needsRequestTag -bedingung nicht erfuellt ist, ist auch das element ungueltig,
        und es wird nicht erzeugt.

        das vorhandensein eines request-tags wird in der variablen @haveRequestTag
        gespeichert. dieses flag kann fuer ein bestimmtes element gesetzt werden, indem
        ihm der wert "requested" zugewiesen wird. normalerweise kann nur DE-elementen
        ein wert zugewiesen werden, diese benoetigen aber kein request-tag. wird also einem
        gruppierenden element der wert "requested" zugewiesen, dann wird das durch die
        methode @c propagateValue() als explizites setzen des @p haveRequestTag
        interpretiert.

        alle klassen und methoden, die also daten fuer die erzeugung von nachrichten
        generieren, muessen u.U. fuer bestimmte syntaxelemente diesen "requested"-wert
        setzen.

        needsRequestTag kann komplett weg, oder? -- nein. F�r GV-Segmente
        gilt das schon. Die �berpr�fung des requested-Werted findet aber
        in der *allgemeinen* SyntaxElement-Klasse statt, wo auch andere
        Segmente (z.b. MsgHead) erzeugt werden. Wenn als "allgemeiner"
        Check der Check "if SEG.isRequested" eingef�hrt werden w�rde, dann
        w�rde der nur bei tats�chlich gew�nschten GV-Segmenten true ergeben.
        Bei MsgHead-Segmenten z.B. w�rde er false ergeben (weil diese
        Segmente niemals auf "requested" gesetzt werden). Deshalb darf diese
        "requested"-�berpr�fung nur bei den Syntaxelementen stattfinden,
        bei denen das explizit gew�nscht ist (needsRequestTag). */
    private boolean needsRequestTag;
    private boolean haveRequestTag;
   
    private void initData(String type, String name, String ppath, int idx, Document syntax)
    {
        if (getElementTypeName().equals("SEG"))
            HBCIUtils.log("creating segment "+ppath+" -> "+name+"("+idx+")", HBCIUtils.LOG_INTERN);
       
        this.type = type;
        this.name = name;
        this.parent=null;
        this.needsRequestTag=false;
        this.haveRequestTag=false;
        this.childContainers = new ArrayList<MultipleSyntaxElements>();
        this.predelim=0;
        this.syntax=syntax;
        this.def=null;
       
        /* der pfad wird gebildet aus bisherigem pfad
         plus name des elementes
         plus indexnummer, falls diese groesser 0 ist */
        StringBuffer temppath=new StringBuffer(128);
        if (ppath!=null && ppath.length()!=0)
            temppath.append(ppath).append(".");
        temppath.append(HBCIUtilsInternal.withCounter(name,idx));
        this.path=temppath.toString();

        setValid(false);

        if (syntax != null) {
            this.def=getSyntaxDef(type,syntax);
           
            // erzeugen der child-elemente
            String requestTag=((Element)def).getAttribute("needsRequestTag");
            if (requestTag!=null && requestTag.equals("1"))
                needsRequestTag=true;

            try {
                int syntaxIdx=0;
                for (Node ref=def.getFirstChild(); ref!=null; ref=ref.getNextSibling()) {
                    if (ref.getNodeType()==Node.ELEMENT_NODE) {
                        MultipleSyntaxElements child=createAndAppendNewChildContainer(ref, syntax);
                        if (child!=null) {
                            child.setParent(this);
                            // TODO: �berpr�fen, ob noch an anderen Stellen Container
                            // erzeugt werden - diese m�ssten dann auch die richtige
                            // syntaxIdx bekommen
                            child.setSyntaxIdx(syntaxIdx);
                           
                            if (getElementTypeName().equals("MSG"))
                                HBCIUtils.log("child container "+child.getPath()+" has syntaxIdx="+child.getSyntaxIdx(), HBCIUtils.LOG_INTERN);
                        }
                        syntaxIdx++;
                    }
                }

                /* durchlaufen aller "value"-knoten und setzen der
                 werte der entsprechenden de */
                // TODO: effizienter: das nicht hier machen, sondern sp�ter,
                // Wenn wir das *hier* machen, dann werden ja DOCH wieder
                // alle "minnum=0"-Segmente
                // erzeugt, weil f�r jedes Segment code und version gesetzt
                // werden m�ssten. Am besten das immer in dem Moment machen,
                // wo ein entsprechendes SyntaxDE erzeugt wird.
                // --> nein, das geht hier. Grund: die optimierte Message-Engine
                // wird nur f�r Segmentfolgen angewendet. Und in Segmentfolgen-
                // Definitionen sind keine values oder valids angegeben, so dass
                // dieser Code hier gar keine Relevanz f�r Segmentfolgen hat
                NodeList valueNodes = ((Element)def).getElementsByTagName("value");
                int      len=valueNodes.getLength();
                String   dottedPath = this.path+".";
                for (int i=0; i<len; i++) {
                    Node   valueNode = valueNodes.item(i);
                    String valuePath = ((Element)valueNode).getAttribute("path");
                    String value     = (valueNode.getFirstChild()).getNodeValue();
                    String destpath  = dottedPath+valuePath;
                   
                    if (!propagateValue(destpath,value,TRY_TO_CREATE,DONT_ALLOW_OVERWRITE))
                        throw new NoSuchPathException(destpath);
                }

                /* durchlaufen aller "valids"-knoten und speichern der valid-values */
                // TODO: das hier ebenfalls sp�ter machen, siehe "values"
                NodeList validNodes=((Element)def).getElementsByTagName("valids");
                len = validNodes.getLength();
                dottedPath = getPath()+".";
                for (int i=0;i<len;i++) {
                    Node validNode=validNodes.item(i);
                    String valuePath=((Element)(validNode)).getAttribute("path");
                    String absPath=dottedPath+valuePath;

                    NodeList validvalueNodes=((Element)(validNode)).getElementsByTagName("validvalue");
                    int len2=validvalueNodes.getLength();
                    for (int j=0;j<len2;j++) {
                        Node validvalue=validvalueNodes.item(j);
                        String value=(validvalue.getFirstChild()).getNodeValue();

                        storeValidValueInDE(absPath,value);
                    }
                }
            } catch (RuntimeException e) {
                for (Iterator<MultipleSyntaxElements> i=getChildContainers().iterator();i.hasNext();) {
                    MultipleSyntaxElements o=i.next();
                    if (o instanceof MultipleSFs) {
                        MultipleSFsFactory.getInstance().unuseObject(o);
                    } else if (o instanceof MultipleSEGs) {
                        MultipleSEGsFactory.getInstance().unuseObject(o);
                    } else if (o instanceof MultipleDEGs) {
                        MultipleDEGsFactory.getInstance().unuseObject(o);
                    } else {
                        MultipleDEsFactory.getInstance().unuseObject(o);
                    }
                }
                throw e;
            }
        }
    }

    /** es wird ein syntaxelement mit der id 'name' initialisiert; der pfad bis zu
        diesem element wird in 'path' uebergeben; 'idx' ist die nummer dieses
        elementes innerhalb der syntaxelementliste fuer dieses element (falls ein
        bestimmtes syntaxelement mehr als einmal auftreten kann) */
    protected SyntaxElement(String type, String name, String path, int idx, Document syntax)
    {
        initData(type,name,path,idx,syntax);
    }

    protected void init(String type, String name, String path, int idx, Document syntax)
    {
        initData(type,name,path,idx,syntax);
    }
   
    protected MultipleSyntaxElements createAndAppendNewChildContainer(Node ref, Document syntax)
    {
        MultipleSyntaxElements ret=createNewChildContainer(ref,syntax);
        if (ret!=null)
            addChildContainer(ret);
        return ret;
    }

    protected boolean storeValidValueInDE(String destPath,String value)
    {
        boolean ret=false;
       
        for (Iterator<MultipleSyntaxElements> i=childContainers.listIterator(); i.hasNext(); ) {
            MultipleSyntaxElements l = i.next();
            if (l.storeValidValueInDE(destPath, value)) {
                ret=true;
                break;
            }
        }

        return ret;
    }

    /** loop through all child-elements; the segments found there
        will be sequentially enumerated starting with num startValue;
        if startValue is zero, the segments will not be enumerated,
        but all given the number 0

        @param startValue value to be used for the first segment found
        @return next sequence number usable for enumeration */
    public int enumerateSegs(int startValue,boolean allowOverwrite)
    {
        int idx = startValue;

        for (Iterator<MultipleSyntaxElements> i = getChildContainers().iterator(); i.hasNext(); ) {
            MultipleSyntaxElements s = i.next();
            if (s != null)
                idx = s.enumerateSegs(idx,allowOverwrite);
        }

        return idx;
    }

    // -------------------------------------------------------------------------------------------
   
    private void initData(String type, String name, String ppath, char predelim, int idx, StringBuffer res, int fullResLen,Document syntax, Hashtable<String,String> predefs,Hashtable<String,String> valids)
    {
        this.type=type;
        this.name=name;
        this.parent=null;
        this.childContainers = new ArrayList<MultipleSyntaxElements>();
        this.predelim = predelim;
        this.needsRequestTag=false;
        this.haveRequestTag=false;
        this.syntax=syntax;
        this.def=null;
        /* position des aktuellen datenelementes berechnet sich aus der
         * gesamtl�nge des urspr�nglichen msg-strings minus der l�nge des
         * reststrings, der jetzt zu parsen ist, und der mit dem aktuellen
         * datenelement beginnt */
        this.posInMsg=fullResLen-res.length();

        StringBuffer temppath=new StringBuffer(128);
        if (ppath!=null && ppath.length()!=0)
            temppath.append(ppath).append(".");
        temppath.append(HBCIUtilsInternal.withCounter(name,idx));
        this.path=temppath.toString();

      setValid(false);

        if (syntax != null) {
            this.def=getSyntaxDef(type,syntax);
           
            /* fuellen der 'predefs'-tabelle mit den in der
             syntaxbeschreibung vorgegebenen werten */
            NodeList valueNodes = ((Element)def).getElementsByTagName("value");
            String dottedPath = getPath() + ".";
            int len=valueNodes.getLength();
            for (int i = 0; i < len; i++) {
                Node valueNode = valueNodes.item(i);
                String valuePath = ((Element)valueNode).getAttribute("path");
                String value = (valueNode.getFirstChild()).getNodeValue();

                predefs.put(dottedPath + valuePath, value);
            }

            if (valids!=null) {
                /* durchlaufen aller "valids"-knoten und speichern der valid-values */
                NodeList validNodes=((Element)def).getElementsByTagName("valids");
                len=validNodes.getLength();
                for (int i=0;i<len;i++) {
                    Node validNode=validNodes.item(i);
                    String valuePath=((Element)(validNode)).getAttribute("path");
                    String absPath=dottedPath+valuePath;
                   
                    NodeList validvalueNodes=((Element)(validNode)).getElementsByTagName("validvalue");
                    int len2=validvalueNodes.getLength();
                    for (int j=0;j<len2;j++) {
                        Node validvalue=validvalueNodes.item(j);
                        String value=(validvalue.getFirstChild()).getNodeValue();
                        valids.put(HBCIUtilsInternal.withCounter(absPath+".value",j),value);
                    }
                }
            }

            try {
                // anlegen der child-elemente
                int counter=0;
                for (Node ref=def.getFirstChild();ref!=null;ref=ref.getNextSibling()) {
                  if (ref.getNodeType()==Node.ELEMENT_NODE) {
                    MultipleSyntaxElements child=parseAndAppendNewChildContainer(ref,
                        ((counter++)==0)?predelim:getInDelim(),
                            getInDelim(),
                            res,fullResLen,syntax,predefs,valids);

                    if (child!=null) {
                      child.setParent(this);

                      // TODO: this is a very very dirty hack to fix the problem with the params-template;
                      // bei der SF "Params", die mit <SF type="Params" maxnum="0"/> referenziert wird,
                      // soll nach jedem erfolgreich in die SF aufgenommenen Param-Segment eine neue
                      // SF begonnen werden, damit das Problem mit dem am Ende der SF stehenden Template-
                      // Param-Segment nicht mehr auftritt
                      // dazu wird beim hinzufuegen von segmenten zur sf ueberprueft, ob diese evtl. bereits
                      // segmente enthaelt (hasValidChilds()). falls das der fall ist, so wird
                      // kein neues segment hinzugefuegt
                      // analoges gilt f�r die SF "GVRes" - hier muss daf�r gesorgt werden, dass jede
                      // antwort in ein eigenes GVRes kommt, damit die zuordnung reihenfolge-erkennung
                      // der empfangenen GVRes-segmente funktioniert (in HBCIJobImpl.fillJobResult())
                      if ((this instanceof SF) &&
                          (getName().equals("Params") || getName().equals("GVRes")) &&
                          ((MultipleSEGs)child).hasValidChilds()) {
                        break;
                      }
                    }
                  }
                }
            } catch (RuntimeException e) {
                for (Iterator<MultipleSyntaxElements> i=getChildContainers().iterator();i.hasNext();) {
                    MultipleSyntaxElements o=i.next();
                    if (o instanceof MultipleSFs) {
                        MultipleSFsFactory.getInstance().unuseObject(o);
                    } else if (o instanceof MultipleSEGs) {
                        MultipleSEGsFactory.getInstance().unuseObject(o);
                    } else if (o instanceof MultipleDEGs) {
                        MultipleDEGsFactory.getInstance().unuseObject(o);
                    } else {
                        MultipleDEsFactory.getInstance().unuseObject(o);
                    }
                }
                throw e;
            }
        }

        // if there was no error until here, this syntaxelement is valid
        setValid(true);
    }

    /** beim parsen: initialisiert ein neues syntaxelement mit der id 'name'; in
        'path' wird der pfad bis zu dieser stelle uebergeben 'predelim' gibt das
        delimiter-zeichen an, das beim parsen vor diesem syntax- element stehen
        muesste 'idx' ist die nummer des syntaxelementes innerhalb der
        uebergeordneten liste (die liste repraesentiert das evtl. mehrmalige
        auftreten eines syntaxelementes, siehe class syntaxelementlist) 'res' ist
        der zu parsende String 'predefs' soll eine menge von pfad-wert-paaren
        enthalten, die fuer einige syntaxelemente den wert angeben, den diese
        elemente zwingend haben muessen (z.b. ein bestimmter segmentcode o.ae.) */
    protected SyntaxElement(String type, String name, String path, char predelim, int idx, StringBuffer res, int fullResLen,Document syntax, Hashtable<String,String> predefs,Hashtable<String,String> valids)
    {
        initData(type,name,path,predelim,idx,res,fullResLen,syntax,predefs,valids);
    }
   
    protected void init(String type, String name, String path, char predelim, int idx, StringBuffer res, int fullResLen,Document syntax, Hashtable<String,String> predefs,Hashtable<String,String> valids)
    {
        initData(type,name,path,predelim,idx,res,fullResLen,syntax,predefs,valids);
    }

    protected MultipleSyntaxElements parseAndAppendNewChildContainer(Node ref, char predelim0, char predelim1, StringBuffer res, int fullResLen, Document syntax, Hashtable<String,String> predefs,Hashtable<String,String> valids)
    {
        MultipleSyntaxElements ret=parseNewChildContainer(ref,predelim0,predelim1,res,fullResLen,syntax,predefs,valids);
        if (ret!=null)
            addChildContainer(ret);
        return ret;
    }

    /** fuellt die hashtable 'values' mit den werten der de-syntaxelemente; dazu
     wird in allen anderen typen von syntaxelementen die liste der
     child-elemente durchlaufen und deren 'fillValues' methode aufgerufen */
    public void extractValues(Hashtable<String,String> values)
    {
        for (Iterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
            MultipleSyntaxElements l = i.next();
            l.extractValues(values);
        }
    }
   
   
    // -------------------------------------------------------------------------------------------
   
    protected void addChildContainer(MultipleSyntaxElements x)
    {
        childContainers.add(x);
    }

    /** @return the ArrayList containing all child-elements (the elements
        of the ArrayList are instances of the SyntaxElementArray class */
    public List<MultipleSyntaxElements> getChildContainers()
    {
        return childContainers;
    }

    /** setzt den wert eines de; in allen syntaxelementen ausser DE wird dazu die
     liste der child-elemente durchlaufen; jedem dieser child-elemente wird der
     wert zum setzen uebergeben; genau _eines_ dieser elemente wird sich dafuer
     zustaendig fuehlen (das DE mit 'path'='destPath') und den wert uebernehmen */
    // TODO: code splitten
    public boolean propagateValue(String destPath, String value, boolean tryToCreate,boolean allowOverwrite)
    {
        boolean ret = false;
       
        if (destPath.equals(getPath())) {
            if (value!=null && value.equals("requested"))
                this.haveRequestTag=true;
            else
                throw new HBCI_Exception(HBCIUtilsInternal.getLocMsg("EXCMSG_INVVALUE",new Object[] {destPath,value}));
            ret=true;
        } else {
            // damit �berspringen wir gleich elemente, bei denen es mit
            // sicherheit nicht funktionieren kann
            if (destPath.startsWith(getPath())) {               
                for (Iterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
                    MultipleSyntaxElements l = i.next();
                    if (l.propagateValue(destPath,value,tryToCreate,allowOverwrite)) {
                        ret = true;
                        break;
                    }
                }
               
                if (!ret && tryToCreate) {
                    // der Wert konnte nicht gesetzt werden -> m�glicherweise
                    // existiert ja nur der entsprechende child-container noch
                    // nicht
                    HBCIUtils.log(getPath()+": could not set value for "+destPath, HBCIUtils.LOG_INTERN);
                   
                    // Namen des fehlenden Elementes ermitteln
                    String subPath=destPath.substring(getPath().length()+1);
                    HBCIUtils.log("  subpath is "+subPath, HBCIUtils.LOG_INTERN);
                    int dotPos=subPath.indexOf('.');
                    if (dotPos==-1) {
                        dotPos=subPath.length();
                    }
                    String subType=subPath.substring(0,dotPos);
                    HBCIUtils.log("  subname is "+subType, HBCIUtils.LOG_INTERN);
                    int counterPos=subType.indexOf('_');
                    if (counterPos!=-1) {
                        subType=subType.substring(0,counterPos);
                    }
                    HBCIUtils.log("  subType is "+subType, HBCIUtils.LOG_INTERN);
                   
                    // hier �berpr�fen, ob es wirklich noch keinen child-container
                    // mit diesem Namen gibt. Wenn z.B. der pfad msg.gv.ueb.kik.blz
                    // gesucht wird und msg.gv schon existiert, wird diese methode
                    // hier in msg.gv ausgef�hrt. wenn sie fehlschl�gt (z.b. weil
                    // tats�chlich kein .ueb.kik.blz angelegt werden kann), wird false
                    // ("can not propagate") zur�ckgegeben. im �bergeordneten modul
                    // (msg) soll dann nicht versucht werden, das n�chste sub-element
                    // (gv) anzulegen - dieser test merkt, dass es "gv" schon gibt
                    boolean found=false;
                    for (Iterator<MultipleSyntaxElements> i=childContainers.iterator();i.hasNext();) {
                        MultipleSyntaxElements c= i.next();
                        if (c.getName().equals(subType)) {
                            found=true;
                            break;
                        }
                    }
                   
                    if (!found) {
                        // jetzt durch alle child-elemente des definierenden XML-Knotens
                        // loopen und den ref-Knoten suchen, der das fehlende Element
                        // beschreibt
                        int     newChildIdx=0;
                        Node    ref=null;
                        found=false;
                        for (ref=def.getFirstChild(); ref!=null; ref=ref.getNextSibling()) {
                            if (ref.getNodeType()==Node.ELEMENT_NODE) {
                                String type=((Element)ref).getAttribute("type");
                                String name=((Element)ref).getAttribute("name");
                                if (name.length()==0) {
                                    name=type;
                                }
                                if (name.equals(subType)) {
                                    found=true;
                                    break;
                                }
                                newChildIdx++;
                            }
                        }

                        if (found) {
                            // entsprechenden child-container erzeugen
                            MultipleSyntaxElements child=createNewChildContainer(ref,syntax);
                            child.setParent(this);
                            child.setSyntaxIdx(newChildIdx);

                            if (getElementTypeName().equals("MSG"))
                                HBCIUtils.log("child container "+child.getPath()+" has syntaxIdx="+child.getSyntaxIdx(),
                                        HBCIUtils.LOG_INTERN);

                            // aktuelle child-container-liste durchlaufen und den neu
                            // erzeugten child-container dort richtig einsortieren
                            int newPosi=0;
                            for (Iterator<MultipleSyntaxElements> i=childContainers.iterator(); i.hasNext(); ) {
                                MultipleSyntaxElements c= i.next();
                                if (c.getSyntaxIdx()>newChildIdx) {
                                    // der gerade betrachtete child-container hat einen idx
                                    // gr��er als den des einzuf�genden elementes, also wird
                                    // sich diese position gemerkt und das element hier eingef�gt
                                    break;
                                }
                                newPosi++;
                            }
                            HBCIUtils.log("  inserting child container with syntaxIdx "+newChildIdx+" at position "+newPosi,
                                    HBCIUtils.LOG_INTERN);
                            childContainers.add(newPosi,child);
                           
                            // now try to propagate the value to the newly created child
                            ret=child.propagateValue(destPath,value,tryToCreate,allowOverwrite);
                        }
                    } else {
                        HBCIUtils.log("  subtype "+subType+" already existing - will not try to create",
                                HBCIUtils.LOG_INTERN);
                    }
                }
            }
        }
       
        return ret;
    }
   
    /** @return den wert eines bestimmten DE;
        funktioniert analog zu 'propagateValue' */
    public String getValueOfDE(String path)
    {
        String ret = null;
       
        for (Iterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
            MultipleSyntaxElements l = i.next();
            ret=l.getValueOfDE(path);
            if (ret!=null) {
                break;
            }
        }

        return ret;
    }

    public String getValueOfDE(String path, int zero)
    {
        String ret = null;
       
        for (ListIterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
            MultipleSyntaxElements l = i.next();
            ret=l.getValueOfDE(path,0);
            if (ret!=null) {
                break;
            }
        }

        return ret;
    }

    /** @param path path to the element to be returned
        @return the element identified by path */
    public SyntaxElement getElement(String path)
    {       
        SyntaxElement ret = null;

        if (getPath().equals(path)) {
            ret=this;
        } else {
            for (ListIterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
                MultipleSyntaxElements l = i.next();
                ret=l.getElement(path);
                if (ret!=null) {
                    break;
                }
            }
        }
       
        return ret;
    }

    protected void setPath(String path)
    {
        this.path = path;
    }

    /** @return the path to this element */
    public final String getPath()
    {
        return path;
    }

    protected void setName(String name)
    {
        this.name = name;
    }

    /** @return the name of this element (i.e. the last component of path) */
    public String getName()
    {
        return name;
    }

    protected void setType(String type)
    {
        this.type = type;
    }

    public String getType()
    {
        return type;
    }

    /** @return the delimiter that must be in front of this element */
    protected char getPreDelim()
    {
        return predelim;
    }
   
    /** @param type the name of the syntaxelement to be returned
        @param syntax the structure containing the current syntaxdefinition
        @return a XML-node with the definition of the requested syntaxelement */
    public final Node getSyntaxDef(String type, Document syntax)
    {
        Node ret = syntax.getElementById(type);
        if (ret == null)
            throw new org.kapott.hbci.exceptions.NoSuchElementException(getElementTypeName(), type);
        return ret;
    }

    /** diese toString() methode wird benutzt, um den wert eines
        de-syntaxelementes in human-readable-form zurueckzugeben. innerhalb eines
        de-elementes wird der wert in der hbci-form gespeichert */
    public String toString(int zero)
    {
        return toString();
    }

    protected final void setValid(boolean valid)
    {
        this.valid = valid;
    }

    public boolean isValid()
    {
        return valid;
    }

    public int checkSegSeq(int value)
    {
        for (Iterator<MultipleSyntaxElements> i=childContainers.iterator();i.hasNext();) {
            MultipleSyntaxElements a= i.next();
            value=a.checkSegSeq(value);
        }

        return value;
    }

    /** ueberpreuft, ob das syntaxelement alle restriktionen einhaelt; ist das
        nicht der fall, so wird eine Exception ausgeloest. die meisten
        syntaxelemente koennen sich nicht selbst ueberpruefen, sondern rufen statt
        dessen die validate-funktion der child-elemente auf */
    public void validate()
    {
        if (!needsRequestTag || haveRequestTag) {
            for (ListIterator<MultipleSyntaxElements> i = childContainers.listIterator(); i.hasNext(); ) {
                MultipleSyntaxElements l = i.next();
                l.validate();
            }

            /* wenn keine exception geworfen wurde, dann ist das aktuelle element
               offensichtlich valid */
            setValid(true);
        }
    }

    public void getElementPaths(Properties p,int[] segref,int[] degref,int[] deref)
    {
    }
   
    public void setParent(MultipleSyntaxElements parent)
    {
        this.parent=parent;
    }

    public MultipleSyntaxElements getParent()
    {
        return parent;
    }
   
    public int getPosInMsg()
    {
        return posInMsg;
    }
   
    protected void destroy()
    {
        childContainers.clear();
        childContainers=null;
        name=null;
        parent=null;
        path=null;
        type=null;
        syntax=null;
        def=null;
    }
}
TOP

Related Classes of org.kapott.hbci.protocol.SyntaxElement

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.