// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.generator; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.util.Map; import java.util.StringTokenizer; import java.util.TreeMap; import java.util.Vector; import org.xml.sax.SAXException; /** * Generates SIFDataObject classes for the SIFWorks ADK.<p> * * This program is for internal use only. It generates the ADK's Data Object * classes by processing metadata definition files (*.xml) that specify how to * build DataObject classes for all versions of SIF supported by the ADK. The * ADKGen program generates a complete set of DataObject class source code and * a SIFDTD class for each version of SIF.<p> * * ADKGen handles multiple versions of SIF by producing a single version- * <i>independent</i> SIFDTD interface class that defines all objects and * fields for all versions of SIF. Version-specific SIFDTD classes are then * created to implement this interface. These version-specific classes are * named the same as the SIF version (e.g. SIF10r1.class, SIF10r2.class, etc.) * ADK developers always interact with the version-independent SIFDTD interface; * internally, the ADK instantiates the appropriate version-specific class * at initialization time. In this way, versioning is mostly transparent to the * developer.<p> * * Each version-specific SIFDTD class (e.g. "openadk.library.impl.SIF10r2") * extends the SIFDTD class of the prior version. Thus, SIF10r2.class would * extend SIF10r1, SIF15r0.class would extend SIF10r2, and so on. These classes * then add ElementDef definitions for objects and fields that were newly * introduced in that version of SIF.<p> * * SIFDataObject implementation classes handle SIF versioning by aggregation. * Any new member functions that are introduced as a result of new or modified * object and fields in the SIF schema are simply added to the existing class. * Enumerated type classes work in the same way. For example, suppose in * SIF 1.0r2 the <Name> element were given a new child element <NickName>, and * the <PreferredName> element were changed to <PrefName>. The * <code>openadk.library.common.Name class</code> would now include the * new member functions setNickName and setPrefName. However, the * setPreferredName method that previously existed for SIF 1.0r1 would remain * intact since ADKGen builds classes by aggregating all versions of SIF into * a single implementation class. Developers could call the setPreferredName() * method if the ADK were initialized for SIF 1.0r1, and could call setPrefName() * if the ADK were initialized for 1.0r2. However, calling setPrefName() for * 1.0r1 would throw a SIFVersionError runtime exception since the <PrefName> * element did not exist in 1.0r1.<p> * * Usage: <code>adkgen [dir | @files] o=output p=package</code><p> * * Where:<p> * * <ul> * <li> * <b>dir</b> is the directory or directories that contain the .xml * definition files imported into ADKGEN. All files ending in *.xml will * be processed. More than one directory can be specified by separating * directories with a semi-colon (e.g. "..\\sif10r1;..\\sif10r2") * </li> * <li> * <b>@files</b> is an optional text file that lists the definition * files to read, one per line. If this file is provided then only the * definition files listed in it will be processed and <i>dir</i> * is ignored. * </li> * <li> * <b>o=output</b> is the root directory where classes are to be generated * </li> * <li> * <b>p=package</b> is the package prefix to use for Data Object * classes that are generated (defaults to "openadk.library") * </li> * </ul> * * @author Eric Petersen * @version 1.0 */ public class Main implements FilenameFilter { public static final long DEFAULT_SERIAL_VERSION_UID = 2; /** The list of definition files to process */ protected Vector<DefinitionFile> fFileList; /** The language to generate output in ( Java or CSharp ) **/ protected String fLanguage = "java"; /** The output directory */ protected String fOutput; /** The package prefix to use for all Data Object classes we generate */ protected String fPackage = "openadk.library"; /** Map of DB objects keyed by SIF version string */ protected Map<String, DB> fDBs = new TreeMap<String, DB>(); /** Static singleton */ public static Main self = null; protected String fFilespec; protected static String fLocale; /** * Constructor * @param args The command-line arguments */ public Main( String[] args ) throws ParseException,SAXException,IOException { self = this; fFilespec = System.getProperty("user.dir"); fLanguage = "java"; fLocale = "us"; for( int i = 0; i < args.length; i++ ) { if( args[i].startsWith("@") ) readFileList(args[i].substring(1)); else if( args[i].startsWith("o=") ) fOutput = args[i].substring(2); else if( args[i].startsWith("l=") ) fLanguage = args[i].substring(2).toLowerCase(); else if( args[i].startsWith("p=") ) fPackage = args[i].substring(2); else if (args[i].startsWith("locale=")) fLocale = args[i].substring(7).toLowerCase(); else fFilespec = args[i]; } if( fOutput == null ) { System.out.println("No o=output parameter specified"); printHelp(); System.exit(-1); } if( !( fLanguage.equals("java") || fLanguage.equals("cs") || fLanguage.equals("zis") || fLanguage.equals("mappings") || fLanguage.equals("stats") || fLanguage.equals("sifdbms") || fLanguage.equals( "jh" ) ) ){ System.out.println("Expected l=java or l=cs or l=jh"); printHelp(); System.exit(-1); } if( !( fLocale.equals("au") || fLocale.equals("uk") || fLocale.equals("us") || fLocale.equals("core")) ){ System.out.println("Expected locale=au or locale=uk or locale=us or locale=core"); printHelp(); System.exit(-1); } if( fFileList == null ) { fFileList = new Vector<DefinitionFile>(); // The input filespec may contain multiple entries separated by // a semi-colon (e.g. "../datadef/sif10r1;../datadef/sif10r2") StringTokenizer tok = new StringTokenizer( fFilespec, ";" ); while( tok.hasMoreTokens() ) { String fs = tok.nextToken(); getFileList(fs); } } // All files created by this tool are placed in one directory. (When // multiple versions of SIF are processed, the results are combined // into one set of source code.) File f = new File(fOutput); System.out.println("Output directory: "+f.getAbsolutePath()); System.out.println("Package: "+fPackage); // Parse all of the .xml files to build the DB[] databases int cnt = fFileList.size(); System.out.println("Processing "+cnt+" files..."); for( int i = 0; i < cnt; i++ ) { (fFileList.elementAt(i)).parse(); } } public static String getLocale() { return fLocale; } public void go() { if( fDBs.size() == 0 ) { System.out.println( "No input files found (or none specified on command-line)" ); System.exit(0); } // Create a single list of DB[] objects to work with int i = 0; DB[] dbs = new DB[fDBs.size()]; fDBs.values().toArray( dbs ); try { // Generate code from each DB Generator g; if( fLanguage.equalsIgnoreCase( "cs" ) ) { g = new CSGenerator(fFilespec,fOutput, fLocale); } else if( fLanguage.equalsIgnoreCase( "zis" ) ) { g = new ZISDefinitionGenerator( fFilespec, fOutput ); } else if( fLanguage.equalsIgnoreCase( "mappings" ) ) { g = new MappingsGenerator( fFilespec, fOutput ); } else if( fLanguage.equalsIgnoreCase( "stats" ) ) { g = new StatsGenerator( fFilespec, fOutput ); } else { // The default behavior is to output java code files g = new JavaGenerator( fFilespec, fOutput ); } g.generate(dbs); } catch( Exception e ) { System.out.println(e); } } /** * Populates the list of definition files by searching a directory for all * files ending with a .xml extension * * @param dir The directory to search * @return The number of files found in the directory */ protected int getFileList( String dir ) throws IOException { File cwd = new File(dir); StringBuffer fs = new StringBuffer(dir); if( !dir.endsWith( File.separator ) ) fs.append( File.separator ); fs.append("*.xml"); System.out.println("Reading file list: "+fs.toString()); File[] files = cwd.listFiles(this); if( files != null ) { for( int i = 0; i < files.length; i++ ) fFileList.addElement( new DefinitionFile(files[i]) ); } System.out.println("Returned : " + files.length + " files...." ); return fFileList.size(); } public boolean accept( File f, String n ) { return n.endsWith(".xml"); } /** * Utility method to populates the list of input .xml files by reading * filenames from a text file. This method is only called when the user * specifies the "@file.txt" option on the command-line. * * @param file The file that lists .xml files to process * @return The number of files listed in the text file */ protected int readFileList( String file ) { BufferedReader in = null; try { System.out.println("Reading file list: "+file); fFileList = new Vector<DefinitionFile>(); in = new BufferedReader( new FileReader(file) ); while( in.ready() ) fFileList.addElement( new DefinitionFile(in.readLine()) ); return fFileList.size(); } catch( Exception e ) { System.out.println("Error reading file '"+file+"': "+e); System.exit(-1); } finally { if( in != null ) { try { in.close(); } catch( Exception ignored ) { } } } return 0; } public static String versionStr( SIFVersion v ) { StringBuffer b = new StringBuffer("SIF"); b.append( String.valueOf( v.getMajor() ) ); b.append( String.valueOf( v.getMinor() ) ); if( v.getRevision() != 0 ) { b.append( 'r' ); b.append( String.valueOf( v.getRevision() ) ); } return b.toString(); } /** * Gets the base package all other packages are relative to * @return A package name (defaults to "openadk.library") */ public static String getPackage() { return self.fPackage; } /** * Gets the DB object associated with the specified version of SIF (or * creates a new object if none currently exists). * @param version The SIF version (e.g. "1.0r1") * @param namespace The namespace defined for that version of SIF (e.g. * "http://www.sifinfo.org/v1.0r2/messages") */ public static DB getDB( SIFVersion version, String namespace ) { DB db = self.fDBs.get(version.toString()); if( db == null ) { db = new DB(version,namespace); self.fDBs.put(version.toString(),db); } return db; } /** * Displays command-line help */ protected void printHelp() { System.out.println("\r\nUsage: adkgen [dir1;dir2;etc. | @files] o=output p=package l=[java|cs|jh|zis] locale=[au|uk|us]"); System.out.println("Example: adkgen ..\\datadef\\sif10r1 o=.. p=openadk.library"); System.out.println("Example: adkgen ..\\datadef\\sif10r1 o=.. p=openadk.library l=cs"); System.out.println("Example: adkgen ..\\datadef\\sif10r1;..\\datadef\\sif10r2"); System.out.println("Example: adkgen @MyFiles.txt o=c:\\adk\\src"); } /** * Main */ public static void main( String[] args ) { System.out.println(); System.out.println("Edustructures SIFWorks ADK"); System.out.println("Data Object Class Generator"); System.out.println("Copyright (c) 2002-2007 Edustructures LLC. All Rights Reserved."); System.out.println("Version 1.1"); System.out.println(); System.out.println("*** For Internal Use Only ***"); System.out.println(); try { Main gen = new Main(args); gen.go(); } catch( Exception e ) { System.out.println(e); } } }