GenerateInitsVisitor { {{ private Hashtable allTypes; private Formatter f; private String reportedPartName = ""; private String accessor = ""; private String inits = ""; }} before CDDef {{ // Generate a list of all "type"s defined in the schema, for later use allTypes = new Hashtable(); for (Enumeration types = host.get_types().elements(); types.hasMoreElements(); ) { DataClass c = (DataClass) types.nextElement(); allTypes.put(c.get_name(), c); } // Initialize the output formatter to create the behavior file for the // initializations visitor f = new Formatter(filename, "Beh", behCodeType); f.open(); f.startClass("InitVisitor"); f.skipLine(); f.declareVariable("private String errors = \"\";"); f.declareVariable("private Hashtable ids = new Hashtable();"); f.skipLine(); }} after CDDef {{ f.startVisitorMethod("after", "XMLDoc"); f.writeTextLine("host.set_element_ids(ids);"); f.endMethod(); f.skipLine(); f.startMethod("public String get_return_val()"); f.writeTextLine("return errors;"); f.endMethod(); f.startMethod("private void addError(String errorText)"); f.writeTextLine("errors = errors + \"\\n\" + errorText;"); f.endMethod(); f.endClass("InitVisitor"); // Close the output formatter f.close(); }} around DataClass {{ // An abstract class is assumed to have no parts, and so do not process // the underlying class-parts if (host.get_abstract_ind()) return; if (host.get_category().equals("SIMPLE")) { if (reportedPartName.equals("")) return; // If it comes here, it must be from the forced traversal in the // getPartInits method subtraversal.apply(); } else { inits = ""; accessor = ""; reportedPartName = ""; f.changeIndent('+'); subtraversal.apply(); f.changeIndent('-'); if (! inits.equals("")) { f.startVisitorMethod("before", host.get_name()); f.writeWithNoIndent(inits); f.endMethod(); } } }} before ClassPart {{ String partName = host.get_name(); String partType = host.get_type(); String partSpec; if (accessor.equals("")) partSpec = "host.get_" + partName + "()"; else { partSpec = accessor + ".get_" + partName + "()"; partName = reportedPartName; } // Get the accessor that would get us to the innermost primitive Java // data type or class, so that basic operations (like ==, <, >, // compareTo(), etc.) can be applied to them. // These might be needed if the constraining facets are defined on a // part with a user-defined simpleType or with a XML built-in data type // that has actually been implemented using a special class (e.g. // XMLpositiveInteger) on which we cannot use "<", for example. String finalPartType = partType; String finalPartSpec = partSpec; String partCategory = ""; DataClass partClass = null; if (! Utils.isPrimitiveDataType(partType)) { partClass = (DataClass) allTypes.get(partType); if (partClass != null) partCategory = partClass.get_category(); if (partCategory.equals("SIMPLE")) { String[] finalModifiers = getFinalModifiers(partType); finalPartType = finalModifiers[0]; finalPartSpec = partSpec + finalModifiers[1]; } } Constraint c = host.get_constraint(); if ((c.id_flag != null) && (c.id_flag.booleanValue())) { inits = inits + "\n" + f.indent() + "if (ids.containsKey(" + finalPartSpec + "))\n"; f.changeIndent('+'); inits = inits + f.indent() + "addError(\"ID (\" + " + finalPartSpec + " + \") in attribute '" + partName + "' has already been used\");\n"; f.changeIndent('-'); inits = inits + f.indent() + "else\n"; f.changeIndent('+'); inits = inits + f.indent() + "ids.put(" + finalPartSpec + ", host);\n"; f.changeIndent('-'); } if (c.default_value != null) { String finalSettorSpec = convertToSettor(finalPartSpec); String settorSpec = convertToSettor(partSpec); inits = inits + "\n" + f.indent() + "if (" + partSpec + " == null)\n" + f.indent() + "{\n"; f.changeIndent('+'); inits = inits + f.indent(); if (Utils.isPrimitiveDataType(finalPartType)) { if (finalPartType.equals("char")) inits = inits + finalSettorSpec + "'" + c.default_value + "');\n"; else inits = inits + finalSettorSpec + c.default_value + ");\n"; } else { if (! finalSettorSpec.equals(settorSpec)) { inits = inits + settorSpec + "new " + partType + "());\n" + f.indent(); } inits = inits + finalSettorSpec + "new " + finalPartType + "(\"" + c.default_value + "\"));\n"; } f.changeIndent('-'); inits = inits + f.indent() + "}\n"; } // if it's a user-defined simple type or a non-Java built-in XML data // type (which is also going to be a simpleType), then locate the // class corresponding to this type and explicitly traverse it here. // This will get the "inits" for the elements in the underlying classes // added as part of the **current** class. if (! Utils.isPrimitiveDataType(partType)) { if (partCategory.equals("SIMPLE")) { boolean firstSimpleType = true; if (accessor.equals("")) reportedPartName = partName; else firstSimpleType = false; String saveInits = inits; // For a list part, we need to iterate over the items and so set // the "accessor" to a local iterator variable name; otherwise // set the "accessor" to the current part-specification // This "accccessor" is used in the subsequent sub-traversal to // represent the data item being validated. if (c.max_occurs > 1) accessor = "e"; else accessor = partSpec; // For a list part (as explained above) we need a "for" loop to // enclose the validations from the sub-traversal; and for an // optional part, we need an "if" statement (checking if the // part is actually present) to enclose the validations. // Accordingly, in these two cases, the indent is to be changed. if ((c.max_occurs > 1) || // if it's a list part (c.min_occurs == 0)) // if it's an optional part f.changeIndent('+'); inits = ""; partClass.getPartInits(this); // If the indent was increased before, reduce it back if ((c.max_occurs > 1) || (c.min_occurs == 0)) f.changeIndent('-'); if (firstSimpleType) // reset the subtraversal indicators { accessor = ""; reportedPartName = ""; } if (! inits.equals("")) { String newInits = saveInits; if (c.max_occurs > 1) // it is a list part { newInits = newInits + "\n" + f.indent() + "for (Enumeration en = " + partSpec + ".elements();\n" + f.indent() + " en.hasMoreElements(); )\n" + f.indent() + "{\n"; f.changeIndent('+'); newInits = newInits + f.indent() + partClass.get_name() + " e = (" + partClass.get_name() + ") en.nextElement();"; f.changeIndent('-'); newInits = newInits + inits + f.indent() + "}\n"; } else if (c.min_occurs == 0) // it is an optional part newInits = newInits + "\n" + f.indent() + "if (" + partSpec + " != null)\n" + f.indent() + "{" + inits + f.indent() + "}\n"; else newInits = newInits + inits; inits = newInits; } else inits = saveInits; } } }} public String getErrors() {{ if (f == null) return "\nInitializations Print visitor action not yet initiated"; else return f.getErrors(); }} private String[] getFinalModifiers(String typeName) {{ String finalType = typeName; String partSpecModifier = ""; while (true) { DataClass partClass = (DataClass) allTypes.get(finalType); if (partClass == null) break; for (Enumeration parts = partClass.get_element_parts().elements(); parts.hasMoreElements(); ) { ElementClassPart e = (ElementClassPart) parts.nextElement(); finalType = e.get_type(); partSpecModifier = partSpecModifier + ".get_" + e.get_name() + "()"; break; } } return new String[] {finalType, partSpecModifier}; }} private String convertToSettor(String partSpec) {{ int lastGetIndex = partSpec.lastIndexOf(".get_"); return (partSpec.substring(0, lastGetIndex+1) + "s" + partSpec.substring(lastGetIndex+2, partSpec.length()-1)); }} } // This traversal method in DataClass is used to do a forced traversal on the // data-class that implements the type of a given class-part. // This separate forced traversal is needed because the current class-part just // contains the name (a string) of the data-class corresponding to its type - it // doesn't have an actual reference to it. // Please note that this data-class would have gotten traversed at some other // time anyway (because the root CDDef has a reference to it in the "types" // list); but this sub-traversal is needed right in the middle of traversing the // class-part, for certain special cases. DataClass { traversal getPartInits(GenerateInitsVisitor) { to *; } }