if (!validated)
{ // Errors in the xml?
if (recOrder.length() == 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "2");
}
if (!recOrder.equals("Arbitrary") && !recOrder.equals("Ordered")
&& !recOrder.equals("Structured"))
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "3");
}
} // if (!validated)
// How to identify the records
String recIdentMethod = linesSpec.getAttribute("RecordIdentification");
if (!validated)
{ // Errors in the xml?
if (recIdentMethod.length() == 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "4");
}
if (!recIdentMethod.equals("TypeIdentifier")
&& !recIdentMethod.equals("RecordOrder"))
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "5");
}
} // if (!validated)
if (recOrder.equals("Arbitrary")
&& !recIdentMethod.equals("TypeIdentifier"))
{
// forbidden combination
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "6");
}
// the record type declarations or ...
// ... the list of record groups, if <recOrder>="Structured"
NodeList recordTypes = linesSpec.getChildNodes();
int numOfRecordTypes = recordTypes.getLength();
// only ok if <recOrder>!="Structured" because otherwise this computes
// the number of record groups!!!!!!!!!
if (recordTypes.getLength() == 0)
{
// Extension if no prior DTD validating
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "7");
}
// Loop will run over record types, but the identification of record
// record groups above is important, as well.
// If <recOrder>!="Structured", the parent node is just the Lines node.
Node recordGroup = linesSpec;
// Now some corrections to the setting so far if record groups must be
// treated.
if (recOrder.equals("Structured"))
{
if (!recIdentMethod.equals("TypeIdentifier")
&& recordTypes.getLength() > 1)
{
// Several record groups are only allowed if the record types
// can
// be identiifed by type identifiers.
// Attention: <recordTypes> contains the record groups - not the
// types!
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "8");
}
numOfRecordTypes = 0;
// For counting the record types a loop over the record groups is
// necessary.
for (int i = 0; i < recordTypes.getLength(); i++)
{ // loop over record groups
if (!recordTypes.item(i).getNodeName().equals("RecordGroup"))
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "9");
}
numOfRecordTypes += recordTypes.item(i).getChildNodes()
.getLength();
// the number of records in that group
} // for (int i=0; i<recordTypes.getLength(); i++)
recordGroup = recordTypes.item(0);
// for loop over record groups
recordTypes = recordGroup.getChildNodes();
// the record types one level deeper now, thus really to record
// types
} // if (recOrder.equals("Structured"))
TreeMap[] existanceIndicators = null;
// for record types which's occurrence depends on a certain value in the
// record before
if (recIdentMethod.equals("TypeIdentifier"))
{ // type identification by type identifier is easy but needs some
// values
// where to find the identifier within the records
String idPos = linesSpec.getAttribute("IdentifierPos");
// Where does the identifier start in the record string?
if (idPos.length() == 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "10");
}
String idLength = linesSpec.getAttribute("IdentifierLength");
// How long is the type identifier?
if (idLength.length() == 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "11");
}
try
{ // The position must be a positive integer.
int num = Integer.parseInt(idPos);
if (num < 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "12");
}
// The length as well must be positive integer.
// Length 0 is permitted for having a simple handling of files
// with
// only one record type.
num = Integer.parseInt(idLength);
if (num < 0)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "13");
}
} // try
catch (ClassCastException e)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "0", e);
} // catch
} // then (recIdentMethod.equals("TypeIdentifier"))
else
// Without type identifiers everything gets more complicated ...
// ... but the primary value are already set.
{ // Indicators for successors may be important.
existanceIndicators = new TreeMap[numOfRecordTypes];
for (int i = 0; i < existanceIndicators.length; i++)
existanceIndicators[i] = null;
// Will be filled when going through the single record type
// declarations.
} // else (recIdentMethod.equals("TypeIdentifier"))
String[] recordTypeNames = new String[numOfRecordTypes];
// Storing the names for consistency check gainst the record type
// specification section.
LinkedList typeIds = new LinkedList();
LinkedList typeIdIntervals = new LinkedList();
// Record type identifier may be single values or intervals.
// They are stored to check their unique reference to a record type.
int recordTypesCount = recordTypes.getLength();
// the number of record types in the current record group or at all
// (wihtout grouping) - at least if no bad nodes are included in a
// errorprone specification
int recordTypesBefore = 0;
// number of record type declarations checked in other record groups
// before - used as offset to datermine the position in the record type
// array
while (recordGroup != null)
{ // loop over record groups
// - only one loop if <recOrder>!="Structured" because of missing
// record groups
for (int i = 0; i < recordTypesCount; i++)
{ // Loop over all record type declarations of the record group
Node rType = recordTypes.item(i);
// Extension if no DTD validating
if (rType.getNodeType() != Node.ELEMENT_NODE
|| !rType.getNodeName().equals("RecordType"))
{
List params = new Vector();
params.add(rType.getNodeName());
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "15", params);
}
// Check the consistency of this single record type declaration.
// If its occurrence depends on values in the prececeeding
// record
// the information about this value is stored in
// <dependenceOnPredecessor>.
String[] dependenceOnPredecessor = checkRecordTypeDeclaration(
rType, recordTypesCount, recordTypesBefore + i,
recIdentMethod, recOrder, recordTypeNames, typeIds,
typeIdIntervals, existanceIndicators);
if (existanceIndicators != null
&& dependenceOnPredecessor != null)
{ // Existance records are expected in general and an
// existance
// indicator is defined for the last cheched record type.
// To ensure that the identification via existance
// indicators
// is possible, the information about them is analysed the
// other
// way round. Originally the information was attached as
// <dependenceOnPredecessor> to the dependent record type.
// Now it will be attached as <existanceIndicators> to its
// possible predecessors.
String occurrences = ((Element) recordTypes.item(i))
.getAttribute("Occurrences");
// Cardinality of the record type.
boolean isOptional = CardinalityStrings
.isCardinalityInterval(occurrences, true)
&& CardinalityStrings.getCardinalityLow(
occurrences, true) == 0;
for (int j = i - 1; j > -1 && isOptional; j++)
{ // Backwards loop to the beginning of the record types
// starting at the predecessor of the examined record
// type.
// As long as a record type is optional, its predecessor
// is
// added to the list of possible predecessors for the
// originally
// checked record type.
// Stops at the first record type because this one may
// not be optional.
// Now information attached to the predecessor.
if (existanceIndicators[j] == null)
{ // The predecessor does not yet have identified
// successor
// which depend on an existnace indicator.
existanceIndicators[j] = new TreeMap();
existanceIndicators[j].put(
dependenceOnPredecessor[0],
dependenceOnPredecessor[1]);
} // then (existanceIndicators[j]==null)
else
{ // The predecessor already has information about
// successors.
// Existance indicator value for the existance
// indicator
// field stated in the examined record type, but
// used for
// another record type !?
String value = (String) existanceIndicators[j]
.get(dependenceOnPredecessor[0]);
if (value != null)
// Existance indicator values in the same field
// for different record types.
if (value.length() != dependenceOnPredecessor[1]
.length())
{
throw new XException(
Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS,
"16");
}
else
// No other use of the existance indicator
// field yet.
// Store the new value.
existanceIndicators[j].put(
dependenceOnPredecessor[0],
dependenceOnPredecessor[1]);
} // else (existanceIndicators[j]==null)
occurrences = ((Element) recordTypes.item(j))
.getAttribute("Occurrences");
// Cardinality of the last checked record type
isOptional = CardinalityStrings.isCardinalityInterval(
occurrences, true)
&& CardinalityStrings.getCardinalityLow(
occurrences, true) == 0;
} // for (int j=i-1; j>-1 && isOptional; j++)
} // if (existanceIndicators!=null &&
// dependenceOnPredecessor!=null)
} // for (int i=0; i<recordTypes.getLength(); i++)
recordTypesBefore += recordTypesCount;
// Correct the number of checked record types in the so far
// examined record groups
if (recordGroup.getNodeName().equals("RecordGroup"))
{ // record groups really present
recordGroup = recordGroup.getNextSibling();
// Choose next record group
if (recordGroup != null)
{ // there is a next record group
recordTypes = recordGroup.getChildNodes();
recordTypesCount = recordTypes.getLength();
// Next check the record types in the new group
} // if (recordGroup != null)
} // if (recordGroup.getNodeName().equals("RecordGroup"))
else
// no real record group loop but record declarations directly
// in lines section, terminate loop by setting ...
recordGroup = null;
} // while (recordGroup!=null) - record group loop
// Check record type names for uniqueness.
for (int i = 0; i < recordTypeNames.length; i++)
for (int j = i + 1; j < recordTypeNames.length; j++)
if (recordTypeNames[i].equals(recordTypeNames[j]))
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "17");
}
// Checks on the type identifier
// First check their length
// If the record type identification is not done by type identifiers,
// the two type id lists are empty.
int identifierLength = 0;
if (typeIds.size() > 0)
// Some single value id's
identifierLength = ((String) typeIds.get(0)).length();
else if (typeIdIntervals.size() > 0)
// No single value id but some id intervals
identifierLength = ((String[]) typeIdIntervals.get(0))[0].length();
// All id's must have the same length.
// First the single value id's
for (int i = 1; i < typeIds.size(); i++)
if (((String) typeIds.get(0)).length() != identifierLength)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "18");
}
// Second the id intervals
for (int i = 1; i < typeIdIntervals.size(); i++)
// Attention: two values!
if (((String[]) typeIdIntervals.get(0))[0].length() != identifierLength
|| ((String[]) typeIdIntervals.get(0))[1].length() != identifierLength)
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "18");
}
// Second, check the id uniqueness in sense of identification of only
// one
// record type
if (!typeIdsAreUnique(typeIds, typeIdIntervals))
{
throw new XException(Constants.LOCATION_INTERN,
Constants.LAYER_PROTOCOL,
Constants.PACKAGE_PROTOCOL_RECORDS, "20");
}
// Return the found record type names and existance indicators.