// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.generator; import java.io.File; import java.io.IOException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * Parses a definition file. * */ public class DefinitionFile implements ErrorHandler { /** * The local package for all classes generated from this file, defined by * the #package directive. This name is used to construct a fully-qualified * package name by concatenating the package prefix specified on the * adkgen command-line with the version of SIF associated with the * definition file. The result is a package name "{prefix}.{version}.{local-package}". * For example, "openadk.library.sif10r1.student" */ protected String fPackage; private String fLocalPackage; /** * The SIF version to which all definitions in this file apply */ protected SIFVersion fVersion; protected String fNamespace; /** The file */ protected File fSrc; protected String fSrcDir; /** The DOM Document */ protected Document fDoc; /** The ObjectDef we're currently processing */ protected ObjectDef fObjectDef; /** The FieldDef we're currently processing */ protected FieldDef fFieldDef; /** The EnumDef we're currently processing */ protected EnumDef fEnumDef; /** The DB object to which all definitions are written */ protected DB fDB; /** Used to assign sequential IDs to <object>'s */ protected int sID = 1; private String fFriendlyName; /** * Constructor */ public DefinitionFile( File f ) { this( f.getAbsolutePath() ); } /** * Constructor */ public DefinitionFile( String f ) { fSrc = new File( f ); fSrcDir = fSrc.getAbsolutePath(); int i = fSrcDir.lastIndexOf( File.separator ); if( i != -1 ) { fSrcDir = fSrcDir.substring(0,i); } } /** * Parses this definition file */ public void parse() throws SAXException,IOException,ParseException { System.out.println("- "+fSrc); org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser(); parser.setErrorHandler(this); parser.parse(fSrc.getAbsolutePath()); Document doc = parser.getDocument(); traverse(doc); } /** * Traverse a node */ public void traverse( Node node ) throws ParseException { // is there anything to do? if( node == null ) return; //Node parent = node.getParentNode(); int type = node.getNodeType(); switch(type) { case Node.DOCUMENT_NODE: { traverse(((Document)node).getDocumentElement()); break; } case Node.ELEMENT_NODE: { String name = node.getNodeName(); if( name.startsWith("adk") ) onRoot(node); else if( name.startsWith("obj") ) onObject(node,false); else if( name.startsWith("enu") ) onEnumeration(node); else if( name.startsWith("att") ) onAttribute(node); else if( name.startsWith("ele") ) onElement(node); else if( name.startsWith("des") ) onDesc(node); else if( name.startsWith("val") ) onValue(node); else if( name.startsWith("inf") ) onObject(node,true); else throw new ParseException("<"+name+"> is not a recognized element"); NodeList children = node.getChildNodes(); if (children != null) { int len = children.getLength(); for (int i = 0; i < len; i++) { traverse(children.item(i)); } } break; } } } protected void onRoot( Node node ) throws ParseException { fLocalPackage = (getAttr(node,"package")); String ver = getAttr(node,"version"); fNamespace = getAttr(node,"namespace"); fFriendlyName = getAttr(node,"name"); if( getLocalPackage() == null || ver == null || fNamespace == null ) throw new ParseException("<adk> must specify the package=, version=, and namespace= attributes"); //TODO: I am ugly String language = Main.self.fLanguage; if ( "java".equals(language) ) { if ( "global".equalsIgnoreCase(fLocalPackage)) { fFriendlyName = "Common"; fLocalPackage = "common"; } else if ( "infrastructure".equalsIgnoreCase(fLocalPackage)) { fFriendlyName = "Infra"; fLocalPackage = "infra"; } } fVersion = SIFVersion.parse(ver); fPackage = Main.getPackage()+"."+getLocalPackage(); System.out.println(" Package="+fPackage); System.out.println(" Version="+ver+" ("+fVersion.toString()+")"); System.out.println(" Namespace="+fNamespace); fDB = Main.getDB(fVersion,fNamespace); fDB.defineDefinitionFile( this ); } protected void onDesc( Node node ) throws ParseException { String desc = getText(node); if( fFieldDef != null ) fFieldDef.setDesc(desc); else if( fObjectDef != null ) fObjectDef.setDesc(desc); } protected void onObject( Node node, boolean infra ) throws ParseException { String name = getAttr(node,"name"); if( name == null ){ throw new ParseException("<object> or <infra> must specify a name= attribute"); } if( infra ) { System.out.println(" Infra: "+name); } else { System.out.println(" Object: "+name); } // if( name.equals( "ProgramFundingSource" ) ){ // System.out.println( "Ready to break" ); // } fObjectDef = fDB.defineObject(sID++,name,getLocalPackage()); if( infra ){ fObjectDef.setInfra(); } fFieldDef = null; fEnumDef = null; String topic = getAttr(node,"topic"); fObjectDef.setTopic( topic != null && ( topic.equalsIgnoreCase("yes") || topic.equalsIgnoreCase("true") ) ); fObjectDef.setRenderAs(getAttr(node,"renderAs")); fObjectDef.setLatestVersion( fVersion ); fObjectDef.setEarliestVersion( fVersion ); if( getBooleanAttr(node,"empty",false) ){ fObjectDef.setFlags( fObjectDef.getFlags() | ObjectDef.FLAG_EMPTYOBJECT ); } if( !getBooleanAttr(node,"sifdtd",true) ){ fObjectDef.setFlags( fObjectDef.getFlags() | AbstractDef.FLAG_NO_SIFDTD ); } if( getBooleanAttr(node,"shared",false) ){ fObjectDef.setShared( true ); } if( getBooleanAttr( node, "collapsed", false ) ){ fObjectDef.setFlags( fObjectDef.getFlags() | ObjectDef.FLAG_OBJECTCOLLAPSED ); } String override = getAttr(node,"sequenceOverride"); if( override != null ) { try { fObjectDef.setSequenceOverride( Integer.parseInt(override) ); } catch( NumberFormatException nfe ) { throw new ParseException( "Invalid sequenceOverride value: " + override ); } } String supercls = getAttr(node,"superclass"); if( supercls == null ) { if( infra ) supercls = "SIFMessagePayload"; else if( fObjectDef.isTopic() ) supercls = "SIFDataObject"; else supercls = "SIFElement"; } String draft = getAttr(node,"draft"); if( draft != null && draft.equalsIgnoreCase("true") ){ fObjectDef.setDraft(); } String typ = getAttr(node,"type"); if( typ != null ){ supercls = typ; } fObjectDef.setSuperclass(supercls); String dataType = getAttr( node, "dataType" ); if( dataType != null ){ fObjectDef.setDataType( dataType ); } String enumType = getAttr( node, "enum" ); if( enumType != null ){ fObjectDef.setEnumType( enumType ); } String extras = getAttr( node,"extras" ); if( extras != null && fObjectDef.getExtrasFile() == null ) { fObjectDef.setExtrasFile( fSrcDir + File.separator + extras ); } } protected void onEnumeration( Node node ) throws ParseException { String name = getAttr(node,"name"); fEnumDef = new EnumDef(name,getLocalPackage()); System.out.println(" Enumeration: "+name); fEnumDef.setLatestVersion( fVersion ); fEnumDef.setEarliestVersion( fVersion ); fDB.defineEnum(name,fEnumDef); } protected void onValue( Node node ) throws ParseException { if( fEnumDef != null ) { String value = getAttr(node,"value"); String desc = getAttr(node,"desc"); String name = getAttr(node,"name"); if( name == null ) name = value; fEnumDef.defineValue(name,value,desc); } } protected void onAttribute( Node node ) throws ParseException { fEnumDef = null; String name = getAttr(node,"name"); String type = getAttr(node,"type"); String flags = getAttr(node,"flags"); String enumVal = getAttr(node,"enum"); StringBuffer out = new StringBuffer(" - "); out.append(name); if( type != null ) { out.append("{"); out.append(type); out.append("}"); } fFieldDef = fObjectDef.defineAttr(name,type); if( flags != null ) fFieldDef.setFlags(flags); if( enumVal != null ){ fFieldDef.setEnum(enumVal); } fFieldDef.setRenderAs( getAttr(node,"renderAs") ); String surrogate = getAttr(node,"surrogate"); if( surrogate != null && !surrogate.endsWith( "}" ) ) { // This should never happen, so throw an exception throw new ParseException( "Surrogate definition '" + surrogate + "' on " + name + " is invalid. Surrogate syntax requires constructor information enclosed by braces {}"); } fFieldDef.setSurrogate( surrogate ); if( ( fFieldDef.getFlags() & AbstractDef.FLAG_MANDATORY ) != 0 && !getBooleanAttr(node,"key",true) ) { // By default all attributes with a "R" flag are used to generate // the object's key. However, some attributes have an "R" flag but // are not part of the key. When the key="false" attribute is // specified, set the FLAG_NOT_A_KEY flag. fFieldDef.setFlags( fFieldDef.getFlags() | FieldDef.FLAG_NOT_A_KEY ); } fFieldDef.setLatestVersion( fVersion ); fFieldDef.setEarliestVersion( fVersion ); System.out.println(out.toString()); } protected void onElement( Node node ) throws ParseException { fEnumDef = null; String name = getAttr(node,"name"); String type = getAttr(node,"type"); String flags = getAttr(node,"flags"); String enumVal = getAttr(node,"enum"); StringBuffer out = new StringBuffer(" > "); out.append(name); if( type != null ) { out.append("{"); out.append(type); out.append("}"); } fFieldDef = fObjectDef.defineElement(name,type); if( flags != null ) fFieldDef.setFlags(flags); if( enumVal != null ){ fFieldDef.setEnum(enumVal); } fFieldDef.setRenderAs( getAttr(node,"renderAs") ); String surrogate = getAttr(node,"surrogate"); if( surrogate != null && !surrogate.endsWith( "}" ) ) { // This should never happen, so throw an exception throw new ParseException( "Surrogate definition '" + surrogate + "' on " + name + " is invalid. Surrogate syntax requires constructor information enclosed by braces {}"); } fFieldDef.setSurrogate( surrogate ); String override = getAttr(node,"sequenceOverride"); if( override != null ) { try { fFieldDef.setSequenceOverride( Integer.parseInt(override) ); } catch( NumberFormatException nfe ) { throw new ParseException( "Invalid sequenceOverride value: " + override ); } } if( !getBooleanAttr(node,"sifdtd",true) ) fFieldDef.setFlags( fFieldDef.getFlags() | AbstractDef.FLAG_NO_SIFDTD ); if( !getBooleanAttr(node,"encode",true) ) fFieldDef.setFlags( fFieldDef.getFlags() | FieldDef.FLAG_DO_NOT_ENCODE ); if( getBooleanAttr( node, "collapsed", false ) ){ fFieldDef.setFlags( fFieldDef.getFlags() | FieldDef.FLAG_COLLAPSED ); } String draft = getAttr(node,"draft"); if( draft != null && draft.equalsIgnoreCase("true") ) fFieldDef.setDraft(); fFieldDef.setLatestVersion( fVersion ); fFieldDef.setEarliestVersion( fVersion ); if( ( fFieldDef.getFlags() & AbstractDef.FLAG_MANDATORY ) != 0 && !getBooleanAttr(node,"key",true) ) { // By default all attributes with a "R" flag are used to generate // the object's key. However, some attributes have an "R" flag but // are not part of the key. When the key="false" attribute is // specified, set the FLAG_NOT_A_KEY flag. fFieldDef.setFlags( fFieldDef.getFlags() | FieldDef.FLAG_NOT_A_KEY ); } System.out.println(out.toString()); fFieldDef.validate(); } protected String getText( Node node ) { if( node != null ) { NodeList ch = node.getChildNodes(); for( int i = 0; i < ch.getLength(); i++ ) { if( ch.item(i).getNodeType() == Node.TEXT_NODE ) return ch.item(i).getNodeValue(); } } return null; } protected String getAttr( Node node, String attr ) { NamedNodeMap attrs = node.getAttributes(); for(int x = 0; x < attrs.getLength(); x++ ){ Node n = attrs.item( x ); if( n.getLocalName().equalsIgnoreCase( attr ) ){ return n.getNodeValue(); } } return null; } protected boolean getBooleanAttr( Node node, String attr, boolean defValue ) { String s = getAttr(node,attr); if( s == null ) return defValue; if( s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes") ) return true; return false; } // // ErrorHandler methods // /** Warning. */ public void warning(SAXParseException ex) { System.err.println("[Warning] at "+ getLocationString(ex)+": "+ ex.getMessage()); } /** Error. */ public void error(SAXParseException ex) { System.err.println("[Error] at "+ getLocationString(ex)+": "+ ex.getMessage()); } /** Fatal error. */ public void fatalError(SAXParseException ex) throws SAXException { System.err.println("[Fatal Error] at "+ getLocationString(ex)); throw ex; } // // Private methods // /** Returns a string of the location. */ private String getLocationString(SAXParseException ex) { StringBuffer str = new StringBuffer(); String systemId = ex.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) systemId = systemId.substring(index + 1); str.append(systemId); } str.append(", Line="); str.append(ex.getLineNumber()); str.append(", Col="); str.append(ex.getColumnNumber()); return str.toString(); } // getLocationString(SAXParseException):String public String getFriendlyName() { return fFriendlyName; } protected String getLocalPackage() { return fLocalPackage; } }