/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.tools.idlgen;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jacorb.idl.AcsAdapterForOldJacorb;
import org.jacorb.idl.AcsInterfacePrinter;
import org.jacorb.idl.AcsJacorbParser;
import org.jacorb.idl.AcsStructPrinter;
import org.jacorb.idl.AcsTypedefPrinter;
import org.jacorb.idl.AliasTypeSpec;
import org.jacorb.idl.Interface;
import org.jacorb.idl.StructType;
import alma.tools.idlgen.comphelpgen.ComponentHelperGeneratorProxy;
/**
* TODO: Update for JacORB!!
*
* Main class of the ACS IDL compiler that produces interfaces, structs, and holders
* for use with XML binding classes.
* The generated code will be similar but different from the output of a regular CORBA IDL compiler.
* IDL interfaces, structs, etc. that contain a field or parameter of type XmlEntityStruct
* will be compiled into source code that contains a corresponding XML binding class.
*
* In collaboration with the other classes from this package, this class * performs the following steps for each IDL file specified: *
typedef
s for the type XmlEntityStruct
,
* e.g. the definition of the type SchedBlock
.
* (see {@link IdlTreeManipulator#findXmlTypedefNodes})SchedBlock
, then
* both IDL structs will get marked.HelperInfo
in the package
* alma.acs.tools.comphelpergen
.* Parameters and properties: *
-verbose
.ACS.idl2jbind
specifies the mappings from typedef'd
* XmlEntityStruct
s to Java binding classes.SchedBlock=alma.xmljbind.test.schedblock.SchedBlock;
* ObsProject=alma.xmljbind.test.obsproject.ObsProject
"
* instructs the compiler to use the Java class
* alma.xmljbind.test.schedblock.SchedBlock
* whereever an XmlEntityStruct
typedef'd to SchedBlock
* is found.alma.acs.tools.comphelpergen.doGenerate
: if true
,
* the ACS IDL compiler will run the generator after compiling an IDL file.
* See {@link alma.tools.idlgen.comphelpgen.ComponentHelperGeneratorProxy}.alma.acs.tools.comphelpergen.outRootDir
specifies the directory under which
* the component helper classes will be generated according to their Java packages.org.openorb.compiler.IdlCompiler
and related classes)
* whereever this is possible.
* No OpenORB code is modified; this goal results in some less
* intuitive handling of parse tree nodes, since new behavior could not be attached to the
* existing classes. On the other hand, we won't have to insert our patches into any new version
* of OpenORB that we might want to use in the future.
* * A half-inspired attempt has been made to pave the road for code generation for languages other than Java. * The tree manipulations could also be used by other code generators. * For Java we reused OpenORB's implementation of the IDL2Java mapping logic * (see {@link JavaGenerator}), but similar generators for other languages would be much more complex. *
* Remark on the proprietary code generation strategy used: * Since OpenORB does not separate IDL2Java mapping logic from Java code generation, we can't * use any standard code generation framework without reimplementing the IDL2Java logic ourselves. * The choice was to accept being different from other ACS code generators, * with the advantage of not writing lots of new code. * * @author hsommer */ public class XmlIdlCompiler { public static final String PROP_DO_GENERATE_COMP_HELPERS = "alma.acs.tools.comphelpergen.doGenerate"; public static final String PROP_COMP_HELPERS_OUTDIR = "alma.acs.tools.comphelpergen.outRootDir"; /** * See {@link #translateFromOpenORB(String[])} about missing verbosity setting coming from the Makefile */ private boolean verbose = false; private final AcsXmlNamingExpert namingExpert; /** * Constructor for XmlIdlCompiler. */ public XmlIdlCompiler() { namingExpert = new AcsXmlNamingExpert(); } /** * This operation is used to generate code for an IDL file that has been parsed already. * @throws Exception */ public void generateCode(JacorbVisitor jacorbVisitor) throws Exception { // -- options that are outside the OpenORB command line option handling String idl2jbindMapping = System.getProperty("ACS.idl2jbind"); namingExpert.setIdlStruct2JavaBindingClassMappings(idl2jbindMapping); boolean doGenerateCompHelpers = Boolean.getBoolean(PROP_DO_GENERATE_COMP_HELPERS); String compHelperOutDir = System.getProperty(PROP_COMP_HELPERS_OUTDIR); if (verbose) { // Print the xml affected nodes System.out.println("\nXML typedefs found: "); for (AliasTypeSpec type : jacorbVisitor.xmlTypedefs) { System.out.println("\t"+type.name()); } System.out.println("\nXML-aware Structs found: "); for (StructType str : jacorbVisitor.xmlAwareStructs) { System.out.println("\t"+str.name()); } System.out.println("\nXML-aware IFs found: "); for (Interface interfce : jacorbVisitor.xmlAwareIFs) { System.out.println("\t"+interfce.name()); } System.out.println("\nXmlIdl options (non-JacORB):" + "\n idl2jbindMapping = " + idl2jbindMapping + "\n doGenerateCompHelpers = " + doGenerateCompHelpers + "\n compHelperOutDir = " + compHelperOutDir); } if (doGenerateCompHelpers && compHelperOutDir == null) { System.err.println("\nCan't generate component helper class(es) because " + "no output directory is given in alma.acs.tools.comphelpergen.outRootDir"); doGenerateCompHelpers = false; } // -- init component helper generator with interfaces and Java packages -- ComponentHelperGeneratorProxy compHelpGen = null; if (doGenerateCompHelpers) { compHelpGen = new ComponentHelperGeneratorProxy(compHelperOutDir, verbose); try { compHelpGen.setOriginalParseTree(jacorbVisitor.acsCompIFs); } catch (RuntimeException e) { System.err.println("failed to parse Java packages:"); System.err.println(e.toString()); System.err.println("Will disable component helper generation."); compHelpGen = null; doGenerateCompHelpers = false; } } else if (verbose) { System.out.println("no code generation for component helper classes was selected..."); } // -- Start to generate Java code, the main purpose of all this -- if (verbose) { System.out.println("\n**** Java code generation ****"); } // -- Rename nodes affected by XML. // -- We do this before starting the code generation to get also nested structs and inherited AcsJ interfaces right. for (Interface interfce : jacorbVisitor.xmlAwareIFs) { interfce.set_name(interfce.name() + "J"); } // Generate code for each xml typedef for (AliasTypeSpec alias : jacorbVisitor.xmlTypedefs) { AcsTypedefPrinter printer = new AcsTypedefPrinter(alias, namingExpert); printer.printHolderClass(); } // Generate code for each xml struct for (StructType struct : jacorbVisitor.xmlAwareStructs) { AcsStructPrinter printer = new AcsStructPrinter(struct, jacorbVisitor.xmlTypedefs, jacorbVisitor.xmlAwareStructs, jacorbVisitor.xmlAwareIFs, namingExpert); printer.printStructClass(); printer.printHolderClass(); } // Generate code for each interface for (Interface interfce : jacorbVisitor.xmlAwareIFs) { AcsInterfacePrinter printer = new AcsInterfacePrinter(interfce, jacorbVisitor.xmlTypedefs, jacorbVisitor.xmlAwareStructs, jacorbVisitor.xmlAwareIFs, namingExpert); printer.printAcsJInterface(); } if (verbose) { System.out.println("\n**** done with Java code generation ****"); } // -- component helper code generation -- if (compHelpGen != null) { System.out.println("ALMA IDL compiler done, now invoking component helper code generator..."); compHelpGen.generateComponentHelperCode(); } } /** * Utility method that creates a File object for code generation. * @throws IOException */ public static File createFile(String jpackage, String className) throws IOException { String fname = className + ".java"; String path = AcsAdapterForOldJacorb.getParserOutDir() + File.separatorChar + jpackage.replace('.', File.separatorChar ); File dir = new File(path); if (!dir.exists()) { if (!dir.mkdirs()) { throw new IOException("Unable to create " + path); } } File f = new File(dir, fname); return f; } /** * The main method gets called from ACS/LGPL/Kit/acs/include/acsMakefileCore.mk * with the following JVM properties and application arguments: *
-d <outputDir>
with the root of the directory tree for the generated output.
* ACS.idl2jbind
that contains the ';'-separated bindings of XmlEntityStruct typedefs
* to XML java binding classes as obtained from the Makefile directive XML_IDL
; alma.acs.tools.comphelpergen.doGenerate and alma.acs.tools.comphelpergen.outRootDir
* - The command line also contains
$(verboseDef)
but it seems to be always empty.
*