Package net.sf.xbus.protocol.records

Source Code of net.sf.xbus.protocol.records.RecordTypeManipulator

package net.sf.xbus.protocol.records;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;

import net.sf.xbus.base.bytearraylist.ByteArrayConverter;
import net.sf.xbus.base.core.Constants;
import net.sf.xbus.base.core.XException;
import net.sf.xbus.base.core.config.Configuration;
import net.sf.xbus.base.xml.XDomSupport;

import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
* <code>RecordTypeManipulator</code> contains all things common to the
* {@link net.sf.xbus.protocol.records.RecordTypeParser RecordTypeParser}and
* {@link net.sf.xbus.protocol.records.RecordTypeSerializer RecordTypeSerializer}.
* The fields concerning the interface structure description are as well shared
* with
* {@link net.sf.xbus.protocol.records.RecordTypeTestDataGenerator RecordTypeTestDataGenerator}.
*
* @author Stephan D�wel
*/
abstract class RecordTypeManipulator
{

  // //////////////////////
  // Object bound fields
  // //////////////////////

  /**
   * <code>sourceType</code> contains the name for the parsed structure as
   * it is derived from a
   * {@link net.sf.xbus.protocol.records.RecordTypeMessage RecordTypeMessage}.
   * <code>RecordTypeManipulator</code> does not garuantee the consistency
   * of <code>sourceType</code>,{@link #contentType}and
   * {@link #interfaceStructure}.
   */
  protected String sourceType;

  /**
   * <code>contentType</code> contains the name for the parsed structure as
   * it is derived from a {@link #interfaceStructure}.
   * <code>RecordTypeManipulator</code> does not garuantee the consistency
   * of <code>contentType</code> and {@link #sourceType}
   */
  protected String contentType;

  /**
   * <code>interfaceStructure</code> holds the structure description used
   * for parsing/serializing. But <code>RecordTypeManipulator</code> does
   * not load the structure description itself from a file nor does it
   * garuantee the consistency of {@link #sourceType}with
   * <code>interfaceStructure</code>.
   */
  protected Document interfaceStructure;

  /**
   * <code>headerSpec</code> is a shortcut into the
   * {@link #interfaceStructure}for the file/string header.
   */
  protected Element headerSpec;

  /**
   * <code>linesSpec</code> is a shortcut into the
   * {@link #interfaceStructure}for the lines specification.
   */
  protected Element linesSpec;

  /**
   * <code>recordTypesSpec</code> is a shortcut into the
   * {@link #interfaceStructure}for the specification section of record
   * types.
   */
  protected Node recordTypesSpec;

  /**
   * <code>trailerSpec</code> is a shortcut into the
   * {@link #interfaceStructure}for the file/string trailer.
   */
  protected Element trailerSpec;

  /**
   * <code>groupsSpec</code> is a shortcut into the
   * {@link #interfaceStructure}for the specification section of field
   * groups.
   */
  protected Node groupsSpec;

  /**
   * <code>recIdentMethod</code> indicates how the records with the parsed
   * string are identified during parsing. Possible values are:
   * <ul>
   * <li>"TypeIdentifier" - The records are identified by a contained id
   * field.</li>
   * <li>"RecordOrder" - The record type is determined by the line order.
   * Works only with <code>recOrder</code> ="Ordered" / "Structured".</li>
   * </ul>
   */
  protected String recIdentMethod;

  /**
   * <code>recOrder</code> determines in which order the differnt record
   * types occurr in the parsed string. Possible values are:
   * <ul>
   * <li>"Arbitrary" - The records are in arbitrary order. Works only with
   * <code>recIdentMethod</code> ="TypeIdentifier".</li>
   * <li>"Ordered" - The records are orderd due to the record type order in
   * this list. Record types - despite of the first one - may be optional.
   * Together with <code>recIdentMethod</code> ="RecordOrder" all optional
   * record types must have an existance indicator.</li>
   * <li>"Structured" - Records of different types belong together and this
   * is expressed by their order. Groups of records appear repeatedly. Each
   * group repects the record type order in this list. Record types - despite
   * of the first one - may be optional. Together with
   * <code>recIdentMethod</code> ="RecordOrder" all optional record types
   * must have an existance indicator.</li>
   * </ul>
   */
  protected String recOrder;

  /**
   * Is the checking of the structrure description activated?
   */
  protected boolean checkingActivated;

  /**
   * The <code>RecordTypeManipulator</code> is able to treat interface file
   * contents as strings or as byte array lists.
   * <code>interfaceContentClass</code> contains the information which of
   * these media is used.
   */
  protected int interfaceContentClass;

  /**
   * For converting between byte arrays and strings. Necessary because
   * internal format for transformations is always string.
   */
  ByteArrayConverter byteArrayConverter;

  /**
   * Length of interface file in sense of <br>
   * (a) characters if the content is represented as string <br>
   * (b) bytes if the content is represented as byte array list
   */
  protected int interfaceContentLength;

  // //////////////////////
  // Constructors
  // //////////////////////

  /**
   * Just the standard constructor.
   */
  protected RecordTypeManipulator() throws XException
  {
    sourceType = null;
    contentType = null;
    interfaceContentClass = Constants.IFCONTENTCLASS_BYTEARRAYLIST;
    // The more complicated case. It will work well even if pure string
    // handling is sufficient.
    interfaceStructure = null;
    headerSpec = null;
    linesSpec = null;
    recordTypesSpec = null;
    trailerSpec = null;
    groupsSpec = null;
    recIdentMethod = null;
    recOrder = null;
    checkingActivated = Configuration.getInstance("xbus")
        .getValueAsBoolean("ParserSettings", "RecordTypeMessage",
            "CheckingActivated");
    // Configuration entry: Should the interface description be checked?
  } // RecordTypeManipulator()

  // //////////////////////
  // Object bound methods
  // //////////////////////

  /**
   * <code>getSourceType</code> retrieves the name for the parsed structure
   * as it is derived from a
   * {@link net.sf.xbus.protocol.records.RecordTypeMessage RecordTypeMessage}.
   * <code>RecordTypeManipulator</code> does not garuantee the consistency
   * of <code>sourceType</code>,{@link #contentType}and
   * {@link #interfaceStructure}.
   */
  public String getSourceType()
  {
    return sourceType;
  } // getSourceType()

  /**
   * <code>getInterfaceContentClass</code> retrieves the mode (string or
   * byte array list) in which the <code>RecordTypeManipulator</code> is
   * working in.
   */
  public int getInterfaceContentClass()
  {
    return interfaceContentClass;
  } // getInterfaceContentClass()

  /**
   * <source>getInterfaceDescription </source> extracts the name of the
   * interface description file.
   *
   * @param system the origin of the message
   * @return name of the interface description file
   * @throws XException in case that the interface file name can not be
   *             retrieved
   */
  protected String getInterfaceDescription(String system) throws XException
  {
    Configuration config = Configuration.getInstance();
    String fileName = config.getValue("System", system, "DescriptionFile");
    return Constants.XBUS_ETC + "InterfaceDescriptions"
        + Constants.FILE_SEPERATOR + fileName;
  } // getInterfaceDescription(XBUSSystem source)

  /**
   * <code>initialize</code> sets the name for the parsed structure and the
   * structure description used for parsing/serializing. The structure
   * description is checked if this option is activated in the configuration.
   * <code>RecordTypeManipulator</code> does not load the structure
   * description itself from a file nor does it garuantee the consistency of
   * {@link #sourceType}with {@link #interfaceStructure}.
   *
   * @param system the name for the parsed structure as it is derived from a
   *            {@link net.sf.xbus.protocol.records.RecordTypeMessage RecordTypeMessage}
   * @param ifContentClass the mode (string or byte array list) in which the
   *            <code>RecordTypeManipulator</code> is working in
   * @param builder ???
   * @throws XException in case of an illegal structure description. In this
   *             case the description is not set!
   */
  public void initialize(String system, int ifContentClass,
      DocumentBuilder builder) throws XException
  {
    String interfaceDescription = getInterfaceDescription(system);
    // The path of the interface description file (xml)
    if (interfaceDescription == null || interfaceDescription.length() == 0)
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "91");
    else
    {
      interfaceStructure = null;
      // For the interface structure parsed from a xml file
      try
      // for casting to XException
      {
        interfaceStructure = builder.parse(interfaceDescription);
        // The record type structure description we have as DOM tree.
      } // try
      catch (IOException e)
      {
        throw new XException(Constants.LOCATION_INTERN,
            Constants.LAYER_PROTOCOL,
            Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
      } // catch (IOException e)
      catch (SAXException e)
      {
        throw new XException(Constants.LOCATION_INTERN,
            Constants.LAYER_PROTOCOL,
            Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
      } // catch (SAXException e)
      // Initialize the parser/serialiser with the interface file type as
      // name
      // and as structure description.
      // This may induce a check on the description file. Some of the
      // checks may be done by validating the document against its DTD.
      // "builder.isValidating()" indicates whether the used parser does
      // such a check.

      try
      // try-catch block for casting standard exceptions to XException
      {
        DocumentType docType = interfaceStructure.getDoctype();
        if (docType != null
            && !docType.getName().equals("InterfaceSpec"))
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "67");
        if (system == null || system.length() == 0)
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "68");
        // content type as derived from a RecordTypeMessage

        Element root = interfaceStructure.getDocumentElement();
        contentType = root.getAttribute("Name");
        // content type as specified in the structure description

        NodeList toplevel = root.getChildNodes();
        int topLevelCount = toplevel.getLength();

        if (topLevelCount < 2)
          // Extension if no prior validating:
          // At least there must be the lines and the record type
          // specs section.
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "69");

        int pos = 0;
        // Counting the top level nodes.

        headerSpec = (Element) toplevel.item(pos);
        // The header is optional.
        if (headerSpec.getNodeName().equals("Header"))
          pos++;
        else
          headerSpec = null;

        linesSpec = (Element) toplevel.item(pos);
        // The lines section is mandatory but a quick check does not
        // harm.
        if (linesSpec.getNodeName().equals("Lines"))
          pos++;
        else
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "70");

        // How to identify the record types
        recIdentMethod = linesSpec.getAttribute("RecordIdentification");
        recOrder = linesSpec.getAttribute("RecordOrder");

        if (pos < topLevelCount)
        { // Some top level nodes left.
          recordTypesSpec = toplevel.item(pos);
          // The record type specifications are mandatory but a quick
          // ckeck does not harm
          if (recordTypesSpec.getNodeName().equals("RecordTypes"))
            pos++;
          else
            throw new XException(Constants.LOCATION_INTERN,
                Constants.LAYER_PROTOCOL,
                Constants.PACKAGE_PROTOCOL_RECORDS, "71");
        } // then (pos<topLevelCount) - before trying record type
        // specifications section
        else
          // The record type specifications are missing.
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "69");

        if (pos < topLevelCount)
        { // Some top level nodes left.
          trailerSpec = (Element) toplevel.item(pos);
          // The trailer is optional.
          if (trailerSpec.getNodeName().equals("Trailer"))
            pos++;
          else
            trailerSpec = null;

          if (pos < topLevelCount)
          {
            groupsSpec = toplevel.item(pos);
            // Field groups may be defined or not.
            if (!groupsSpec.getNodeName().equals("Groups"))
            { // Unexpected tag.
              List params = new Vector();
              params.add(groupsSpec.getNodeName());
              params.add("Groups");
              throw new XException(Constants.LOCATION_INTERN,
                  Constants.LAYER_PROTOCOL,
                  Constants.PACKAGE_PROTOCOL_RECORDS, "85",
                  params);
            } // if (!groupsSpec.getNodeName().equals("Groups"))
          } // if (pos<topLevelCount) - before trying groups section
        } // if (pos<topLevelCount) - before trying trailer

        if (checkingActivated)
        { // Check structure description for consistency refering to
          // the
          // single parts.
          RecordTypeDescriptionChecker checker = RecordTypeDescriptionChecker
              .getInstance();

          if (headerSpec != null)
            checker.checkHeaderSpecification(headerSpec,
                groupsSpec, builder.isValidating());

          Object[] checkInfos = checker.checkLinesSpecification(
              linesSpec, builder.isValidating());
          // record type names and existance indicator declarations
          // stored for
          // further consistency checks

          // Check the record type specifications.
          // In particular mark in <checkInfos> all specified record
          // types
          // and all existance indicators pointing to an existing
          // field.
          checker.checkRecordTypesSpecification(recordTypesSpec,
              groupsSpec, checkInfos, builder.isValidating());

          // Everthing in <checkInfos> found?
          for (int i = 0; i < ((String[]) checkInfos[0]).length; i++)
            if (((String[]) checkInfos[0])[i] != null)
            { // <null> indicates that the declared record type is
              // specified.
              List params = new Vector();
              params.add(((String[]) checkInfos[0])[i]);
              throw new XException(Constants.LOCATION_INTERN,
                  Constants.LAYER_PROTOCOL,
                  Constants.PACKAGE_PROTOCOL_RECORDS, "74",
                  params);
            } // if (((String[]) checkInfos[0])[i] != null)

          // Existance indicators as second checkInfos component
          // are optional: not used if
          // <recIdentMethod>=="TypeIdentifier".
          if (checkInfos[1] != null)
          { // <checkInfos[1]> contains all existance indicators
            // which
            // point from any record type to any other.
            for (int i = 0; i < ((TreeMap[]) checkInfos[1]).length; i++)
            { // loop over all record types in the role of a
              // preceding
              // record containg an existance indicator for a
              // suceeding
              // record type
              TreeMap existanceIndicators = ((TreeMap[]) checkInfos[1])[i];
              // the existance indicators from one specific record
              // type to others
              if (existanceIndicators != null)
              { // some existance indicators depending on fields
                // on
                // this record type
                // Look if all of them point to existing fields.
                Iterator it = existanceIndicators.values()
                    .iterator();
                while (it.hasNext())
                { // loop over all existance indicators for
                  // each
                  // record type
                  String value = (String) it.next();
                  if (!value.equals("Found"))
                  { // "Found" indicates that the respective
                    // field specification exists.
                    List params = new Vector();
                    params.add(value);
                    throw new XException(
                        Constants.LOCATION_INTERN,
                        Constants.LAYER_PROTOCOL,
                        Constants.PACKAGE_PROTOCOL_RECORDS,
                        "75", params);
                  } // if (!value.equals("Found"))
                } // while (it.hasNext())
              } // if (existanceIndicators!=null)
            } // for (int i=0;
              // i<((TreeMap[])checkInfos[1]).length;
            // i++)
          } // if (checkInfos[1]!=null)

          if (trailerSpec != null)
            checker.checkTrailerSpecification(trailerSpec,
                groupsSpec, builder.isValidating());

          if (groupsSpec != null)
            checker.checkGroupsSpecification(groupsSpec, builder
                .isValidating());
        } // if (checkingActivated)

        // Everything checked - if desired - thus store the structure
        // information
        sourceType = system;

        // the working mode details (string / byte array list)
        interfaceContentClass = ifContentClass;
        byteArrayConverter = getByteArrayConverter();
      } // try
      catch (Exception e) // i.e. DOMException, ClassCastException
      {
        throw new XException(Constants.LOCATION_INTERN,
            Constants.LAYER_PROTOCOL,
            Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
      } // catch
    } // else (interfaceDescription==null ||
    // interfaceDescription.length()==0)
  } // initialize(String system, int ifContentClass, DocumentBuilder
    // builder)

  /**
   * <code>getByteArrayConverter</code> retrieves a byte array converter
   * (conversion between strings and byte arrays) according to the specific
   * interface needs. Its is abstract because subclasses use different ways of
   * determining the correct interface name.
   *
   * @return ByteArrayConverter for string-byte array conversion in the
   *         specific interface situation
   */
  abstract protected ByteArrayConverter getByteArrayConverter()
      throws XException;

  /**
   * <code>getRecordTypePositionInLines</code> retrieves the position of a
   * record type in the lines section.
   *
   * @param recordType as node in the lines section
   * @return the position of the record type in the lines section (starting at
   *         0) - relative to the record group if {@link #recOrder}
   *         =="Structured"
   * @throws XException in case that the record type cannot be found
   */
  protected int getRecordTypePositionInLines(Element recordType)
      throws XException
  {
    int pos = -1;
    // for the position
    NodeList recordTypes = recordType.getParentNode().getChildNodes();
    // Complicated to serve for both situations - with and without record
    // groups
    for (int i = 0; i < recordTypes.getLength() && pos == -1; i++)
      // loop over record type declarations below the same parent node
      if (XDomSupport.getTrimedNodeText(recordTypes.item(i)).equals(
          XDomSupport.getTrimedNodeText(recordType)))
        // Found
        pos = i;
    if (pos == -1)
    {
      List params = new Vector();
      params.add(XDomSupport.getTrimedNodeText(recordType));
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "77", params);
    }
    return pos;
  } // getPositionInLines(Element recordType)

  /**
   * <code>getRecordTypeByID</code> retrieves the record type declaration
   * within the lines section by the type identifier.
   *
   * @param searchedId the type identifier
   * @return the record type declaration node in the lines section as as
   *         {@link org.w3c.dom.Element}
   * @throws XException in case that the record type cannot be found
   */
  protected Element getRecordTypeById(String searchedId) throws XException
  {
    Node recordGroup = linesSpec;
    if (recOrder.equals("Structured"))
      // Go to record group level
      recordGroup = linesSpec.getFirstChild();
    Element result = null;
    try
    // for casting to XException
    {
      while (recordGroup != null && result == null)
      { // loop over record groups
        NodeList recordTypes = recordGroup.getChildNodes();
        // record types in this group
        for (int i = 0; i < recordTypes.getLength() && result == null; i++)
        { // loop over record types in the group
          result = (Element) recordTypes.item(i);
          String id = result.getAttribute("Identifier");
          if (id.length() > 0)
          { // type id specified as single value
            if (!id.equals(searchedId))
              // not the right one
              result = null;
          } // then (id.length()>0)
          else
          { // type id specified as interval
            String idLo = result.getAttribute("IdentifierLow");
            String idHi = result.getAttribute("IdentifierHigh");
            if (idLo.length() == 0 || idHi.length() == 0
                || idLo.compareTo(searchedId) > 0
                || idHi.compareTo(searchedId) < 0)
              // searched id not comtained in interval
              result = null;
          } // else (id.length()>0)
        } // for (int i=0; i<recordTypes.getLength()&&result==null;
          // i++)

        if (recordGroup.getNodeName().equals("RecordGroup"))
          // Next record group
          recordGroup = recordGroup.getNextSibling();
        else
          // If there are nor groups, just finish the record group
          // loop
          recordGroup = null;
      } // while (recordGroup!=null && result==null)
    } // try
    catch (ClassCastException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch
    if (result == null)
    {
      List params = new Vector();
      params.add(searchedId);
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "79", params);
    }
    return result;
  } // getRecordTypePosById(String searchedId)

  /**
   * <code>getRecordTypeSpec</code> retrieves the record type specification
   * from the record types section to a record type name.
   *
   * @param recordType the record type name
   * @return the record type specification as {@link org.w3c.dom.Node node}in
   *         the interface structure description
   * @throws XException in case that the record type specification cannot be
   *             found
   */
  protected Node getRecordTypeSpec(String recordType) throws XException
  {
    try
    // for casting to XException
    {
      List candidates = XDomSupport.getChildNodesByAttrValue(
          recordTypesSpec, "Name", recordType, "RecordTypeSpec");
      if (candidates.size() != 1)
      {
        List params = new Vector();
        params.add(recordType);
        throw new XException(Constants.LOCATION_INTERN,
            Constants.LAYER_PROTOCOL,
            Constants.PACKAGE_PROTOCOL_RECORDS, "80", params);
      } // if (candidates.size() != 1)
      return (Node) candidates.get(0);
    } // try
    catch (ClassCastException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch
  } // getRecordTypeSpec(String recordType)

  /**
   * <code>getFieldPos</code> determines the position of a field within the
   * surrounding record type - including header and trailer.
   *
   * @param fieldSpec the field as {@link org.w3c.dom.Element elementnode}
   * @param parentSpec the specification of the surrounding record type
   * @return the field position within the record type
   * @throws XException in case of problems with the description file
   */
  protected int getFieldPos(Element fieldSpec, Node parentSpec)
      throws XException
  {
    int pos = 0;
    // for the result
    boolean searching = true;
    try
    // for casting to XException
    {
      String fieldName = fieldSpec.getAttribute("Name");
      if (fieldName == null || fieldName.length() == 0)
      {
        List params = new Vector();
        params.add("Name");
        params.add(((Element) fieldSpec.getParentNode())
            .getAttribute("Name"));
        params.add(fieldSpec.toString());
        throw new XException(Constants.LOCATION_INTERN,
            Constants.LAYER_PROTOCOL,
            Constants.PACKAGE_PROTOCOL_RECORDS, "82", params);
      } // if (fieldName == null || fieldName.length() == 0)
      NodeList fieldSpecs = parentSpec.getChildNodes();
      for (int i = 0; i < fieldSpecs.getLength() && searching; i++)
      { // loop over fields and group references within record type
        Element searchedFieldSpec = (Element) fieldSpecs.item(i);
        if (searchedFieldSpec.getNodeName().equals("Field"))
          // a single field, compare its name
          if (fieldName
              .equals(searchedFieldSpec.getAttribute("Name")))
            searching = false;
          else
            pos++;
        else if (searchedFieldSpec.getNodeName().equals("Group"))
        { // an entire field group
          NodeList groupFields = RecordTypeDescriptionChecker
              .getGroupSpec(
                  searchedFieldSpec.getAttribute("Name"),
                  groupsSpec).getChildNodes();
          for (int j = 0; j < groupFields.getLength(); j++)
          { // loop over group fields
            searchedFieldSpec = (Element) groupFields.item(j);
            // now a single field, compare its name
            if (fieldName.equals(searchedFieldSpec
                .getAttribute("Name")))
              searching = false;
            else
              pos++;
          } // for (int j=0; j<groupFields.getLength(); j++)
        } // if (searchedFieldSpec.getNodeName().equals("Group"))
      } // for (int i=0; i<fieldSpecs.getLength()&&searching; i++)
    } // try
    catch (ClassCastException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch
    if (searching)
    { // Field not found
      List params = new Vector();
      params.add(((Element) fieldSpec.getParentNode())
          .getAttribute("Name"));
      params.add(fieldSpec.getAttribute("Name"));
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "84", params);
    }
    return pos;
  } // getFieldPos(Element fieldSpec, Node parentSpec)

  /**
   * <code>getTypeIdentifier</code> retrieves the type identifier field.
   *
   * @param idPosString the identifier position in the record line - in sense
   *            of char counting if the interface contant is treated as
   *            string; in sense of byte counting if a byte array list is used
   *            instead
   * @param recordTypeSpec the record type specification to search in
   * @return the name of the type identifier field - null if it could not be
   *         found
   * @throws XException in case of problems with the description file or the
   *             identifier position
   */
  protected String getTypeIdentifier(String idPosString, Node recordTypeSpec)
      throws XException
  {
    String result = null;
    try
    // for casting to XException
    { // the identifier position
      int idPos = Integer.parseInt(idPosString);
      // the field specifications
      NodeList fields = recordTypeSpec.getChildNodes();
      int i = 0;
      int[] pos =
      {0};
      // the search position - array for call by reference to search in
      // groups
      for (; result == null && i < fields.getLength() && pos[0] <= idPos; i++)
      { // loop over fields until identifier position is reached
        Element fieldSpec = (Element) fields.item(i);
        if (fieldSpec.getNodeName().equals("Field"))
          // a single field
          if (pos[0] == idPos)
            // identifier position reached
            result = fieldSpec.getAttribute("Name");
          else
            // Go further.
            pos[0] += Integer.parseInt(fieldSpec
                .getAttribute("Length"));
        else if (fieldSpec.getNodeName().equals("Group"))
          // an entire field group
          result = getTypeIdentifierFromGroup(idPos, fieldSpec, pos);
        else
        {
          List params = new Vector();
          params.add(fieldSpec.getNodeName());
          params.add("Field or Group");
          throw new XException(Constants.LOCATION_INTERN,
              Constants.LAYER_PROTOCOL,
              Constants.PACKAGE_PROTOCOL_RECORDS, "85", params);
        } // else (fieldSpec.getNodeName().equals("Group"))
      } // for (; i<fields.getLength()&&pos[0]<=idPos; i++)
    } // try
    catch (NumberFormatException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch (NumberFormatException e)
    catch (ClassCastException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch (ClassCastException e)
    return result;
  } // getTypeIdentifier(String idPosInString, Node recordTypeSpec)

  /**
   * <code>getTypeIdentifierFromGroup</code> searches the type identifier
   * field within a field group.
   *
   * @param idPos the identifier position in the record line - in sense of
   *            char counting if the interface contant is treated as string;
   *            in sense of byte counting if a byte array list is used instead
   * @param groupRef the group reference
   * @param pos the actual search position, will be augmented - array for call
   *            by reference
   * @return the name of the type identifier field - null if it could not be
   *         found
   * @throws XException in case of problems with the description file
   */
  private String getTypeIdentifierFromGroup(int idPos, Element groupRef,
      int[] pos) throws XException
  {
    try
    // for casting to XException
    { // the group fields
      NodeList fieldSpecs = RecordTypeDescriptionChecker.getGroupSpec(
          groupRef.getAttribute("Name"), groupsSpec).getChildNodes();
      // fields in the group
      for (int i = 0; i < fieldSpecs.getLength() && pos[0] <= idPos; i++)
      { // Loop over group fields until identifier position is reached
        Element fieldSpec = (Element) fieldSpecs.item(i);
        // identifier position reached
        if (pos[0] == idPos)
          fieldSpec.getAttribute("Name");
        else
          // Go further.
          pos[0] += Integer
              .parseInt(fieldSpec.getAttribute("Length"));
      } // for (int i=0; i<fieldSpecs.getLength(); i++)
    } // try
    catch (NumberFormatException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch (NumberFormatException e)
    catch (ClassCastException e)
    {
      throw new XException(Constants.LOCATION_INTERN,
          Constants.LAYER_PROTOCOL,
          Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
    } // catch
    return null;
  } // getTypeIdentifierFromGroup(int idPos, Element groupRef, int[] pos)

} // RecordTypeManipulator
TOP

Related Classes of net.sf.xbus.protocol.records.RecordTypeManipulator

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.