/* * JacORB - a free Java ORB * * Copyright (C) 1997-2014 Gerald Brose / The JacORB Team. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.jacorb.idl; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.logging.Level; /** * @author Andre Spiegel */ public class ValueDecl extends Value { private MemberList stateMembers; private List operations; private List exports; private List factories; private ValueInheritanceSpec inheritanceSpec; // some flags... private boolean isCustomMarshalled = false; private boolean hasStatefulBases = false; private boolean hasBody = false; /** public c'tor, called by parser */ public ValueDecl(int num) { super(num); stateMembers = new MemberList(new_num()); operations = new ArrayList(); exports = new ArrayList(); factories = new ArrayList(); } public void setValueElements(Definitions d) { hasBody = true; for(Iterator i = d.v.iterator(); i.hasNext();) { Declaration dec = ((Definition)(i.next())).get_declaration(); dec.setPackage(name); if (dec instanceof StateMember) stateMembers.v.add(dec); else if (dec instanceof OpDecl) operations.add(dec); else if (dec instanceof InitDecl) factories.add(dec); else exports.add(dec); } stateMembers.setContainingType(this); stateMembers.setPackage(name); stateMembers.setEnclosingSymbol(this); for(Iterator i = operations.iterator(); i.hasNext();) ((OpDecl)i.next()).setEnclosingSymbol(this); for(Iterator i = exports.iterator(); i.hasNext();) ((IdlSymbol)i.next()).setEnclosingSymbol(this); for(Iterator i = factories.iterator(); i.hasNext();) ((IdlSymbol)i.next()).setEnclosingSymbol(this); } public void setInheritanceSpec(ValueInheritanceSpec spec) { inheritanceSpec = spec; } public ValueInheritanceSpec getInheritanceSpec() { return inheritanceSpec; } public void isCustomMarshalled(boolean flag) { this.isCustomMarshalled = flag; } public boolean isCustomMarshalled() { return this.isCustomMarshalled; } public void setPackage(String s) { s = parser.pack_replace(s); if (pack_name.length() > 0) pack_name = s + "." + pack_name; else pack_name = s; stateMembers.setPackage(s); if (inheritanceSpec != null) inheritanceSpec.setPackage(s); for(Iterator i = operations.iterator(); i.hasNext();) ((IdlSymbol)i.next()).setPackage(s); for(Iterator i = exports.iterator(); i.hasNext();) ((IdlSymbol)i.next()).setPackage(s); for(Iterator i = factories.iterator(); i.hasNext();) ((IdlSymbol)i.next()).setPackage(s); } public TypeDeclaration declaration() { return this; } public void parse() { if (inheritanceSpec != null) { inheritanceSpec.parse(); } boolean justAnotherOne = false; if (isCustomMarshalled() && inheritanceSpec != null && inheritanceSpec.truncatable != null) { parser.error("Valuetype " + typeName() + " may no be BOTH custom AND truncatable", token); } ConstrTypeSpec ctspec = new ConstrTypeSpec(new_num()); try { escapeName(); ScopedName.definePseudoScope(full_name()); ctspec.c_type_spec = this; NameTable.define(full_name(), IDLTypes.TYPE); TypeMap.typedef(full_name(), ctspec); } catch (NameAlreadyDefined nad) { Object forwardDeclaration = parser.get_pending (full_name ()); if (forwardDeclaration != null) { if (! (forwardDeclaration instanceof ValueDecl)) { parser.error("Forward declaration types mismatch for " + full_name() + ": name already defined with another type" , token); } if (stateMembers.size () != 0) { justAnotherOne = true; } if (! full_name().equals("org.omg.CORBA.TypeCode") && stateMembers.size () != 0) { TypeMap.replaceForwardDeclaration(full_name(), ctspec); } } else { parser.error("Valuetype " + typeName() + " already defined", token); } } if (hasBody) { parser.logger.log(Level.WARNING, "valueDecl.parse(): exports (but not attributes)"); // parse exports Iterator iter = exports.iterator(); while(iter.hasNext()) { IdlSymbol idlSymbol = (IdlSymbol)iter.next(); if (! ( idlSymbol instanceof AttrDecl ) ) { idlSymbol.parse(); } } parser.logger.log(Level.WARNING, "valueDecl.parse(): members"); ScopedName.addRecursionScope(typeName()); stateMembers.parse(); ScopedName.removeRecursionScope(typeName()); parser.logger.log(Level.WARNING, "valueDecl.parse(): operations"); // parse operations iter = operations.iterator(); while(iter.hasNext()) { IdlSymbol idlSymbol = (IdlSymbol)iter.next(); idlSymbol.parse(); } parser.logger.log(Level.WARNING, "valueDecl.parse(): exports(attributes)"); // parser exports iter = exports.iterator(); while(iter.hasNext()) { IdlSymbol idlSymbol = (IdlSymbol)iter.next(); if (idlSymbol instanceof AttrDecl) { idlSymbol.parse(); Enumeration e = ((AttrDecl)idlSymbol).getOperations(); while(e.hasMoreElements()) { operations.add(e.nextElement()); } } } parser.logger.log(Level.WARNING, "valueDecl.parse(): factories"); // parse factories iter = factories.iterator(); while(iter.hasNext()) { IdlSymbol idlSymbol = (IdlSymbol)iter.next(); idlSymbol.parse(); } // check inheritance rules parser.logger.log(Level.WARNING, "valueDecl.parse(): check inheritance"); if (inheritanceSpec != null) { HashSet h = new HashSet(); for(Enumeration e = inheritanceSpec.getValueTypes(); e.hasMoreElements();) { ScopedName scopedName = (ScopedName)e.nextElement(); ConstrTypeSpec ts = unwindTypedefs(scopedName); if (ts.declaration() instanceof Value) { if (h.contains(ts.full_name())) { parser.fatal_error("Illegal inheritance spec: " + inheritanceSpec + " (repeated inheritance not allowed).", token); } // else: h.add(ts.full_name()); continue; } parser.logger.log(Level.SEVERE, " Declaration is " + ts.declaration().getClass()); parser.fatal_error("Non-value type in inheritance spec: " + Environment.NL + "\t" + inheritanceSpec, token); } for(Enumeration e = inheritanceSpec.getSupportedInterfaces(); e.hasMoreElements();) { ScopedName scopedName = (ScopedName)e.nextElement(); ConstrTypeSpec ts = (ConstrTypeSpec)scopedName.resolvedTypeSpec().typeSpec(); if (ts.declaration() instanceof Interface) { continue; } parser.fatal_error("Non-interface type in supported interfaces list: " + Environment.NL + "\t" + inheritanceSpec, token); } } NameTable.parsed_interfaces.put(full_name(), ""); parser.remove_pending(full_name()); } else if (! justAnotherOne) { // i am forward declared, must set myself as // pending further parsing parser.set_pending(full_name(), this); } } private ConstrTypeSpec unwindTypedefs(ScopedName scopedName) { TypeSpec resolvedTSpec = scopedName.resolvedTypeSpec(); //unwind any typedefs while (resolvedTSpec instanceof AliasTypeSpec ) { resolvedTSpec = ((AliasTypeSpec)resolvedTSpec).originalType(); } if (! (resolvedTSpec instanceof ConstrTypeSpec)) { if (parser.logger.isLoggable(Level.ALL)) { parser.logger.log(Level.ALL, "Illegal inheritance spec, not a constr. type but " + resolvedTSpec.getClass() + ", name " + scopedName); } parser.fatal_error("Illegal inheritance spec (not a constr. type): " + inheritanceSpec, token); } return (ConstrTypeSpec) resolvedTSpec; } public void setEnclosingSymbol(IdlSymbol s) { if (enclosing_symbol != null && enclosing_symbol != s) { parser.logger.log(Level.SEVERE, "was " + enclosing_symbol.getClass().getName() + " now: " + s.getClass().getName()); throw new RuntimeException("Compiler Error: trying to reassign container for " + name); } enclosing_symbol = s; } public void set_included(boolean i) { included = i; } public boolean basic() { return true; } public String toString() { return full_name(); } public String holderName() { return javaName() + "Holder"; } public String helperName() { return javaName() + "Helper"; } public String typeName() { return full_name(); } public String getTypeCodeExpression() { return this.getTypeCodeExpression(new HashSet()); } public String getTypeCodeExpression(Set knownTypes) { if (knownTypes.contains(this)) { return this.getRecursiveTypeCodeExpression(); } String baseType = "null"; // Only add e.g. FooHelper.type() for those inherited non-abstract ValueTypes. if (hasStatefulBases && inheritanceSpec != null && inheritanceSpec.v.size() > 0) { baseType = ((ScopedName)inheritanceSpec.v.get(0)).resolvedName() + "Helper.type()"; } StringBuffer result = new StringBuffer ("org.omg.CORBA.ORB.init().create_value_tc (" + // id, name "\"" + id() + "\", " + "\"" + name + "\", " + // type modifier "(short)" + (this.isCustomMarshalled() ? org.omg.CORBA.VM_CUSTOM.value : org.omg.CORBA.VM_NONE.value ) + ", " + // concrete base type baseType + ", " + // value members "new org.omg.CORBA.ValueMember[] {"); knownTypes.add(this); for(Iterator i = stateMembers.v.iterator(); i.hasNext();) { Set knownTypesLocal = new HashSet(knownTypes); StateMember m = (StateMember)i.next(); result.append(getValueMemberExpression(m, knownTypesLocal)); if (i.hasNext()) result.append(", "); } knownTypes.remove(this); result.append("})"); return result.toString(); } private String getValueMemberExpression(StateMember m, Set knownTypes) { TypeSpec typeSpec = m.typeSpec(); //if the type is not a basic type and is in the typeMap //use the typeSpec saved within the TypeMap if (typeSpec.full_name() != null && !typeSpec.full_name().equals("IDL:*primitive*:1.0") && TypeMap.typemap.containsKey(typeSpec.full_name())) typeSpec = TypeMap.map(typeSpec.full_name()); String memberTypeExpression = typeSpec.getTypeCodeExpression(knownTypes); short access = m.isPublic ? org.omg.CORBA.PUBLIC_MEMBER.value : org.omg.CORBA.PRIVATE_MEMBER.value; return "new org.omg.CORBA.ValueMember (" + "\"" + m.name + "\", \"" + typeSpec.id() + "\", \"" + name + "\", \"1.0\", " + memberTypeExpression + ", null, " + "(short)" + access + ")"; } public void print(PrintWriter ps) { // no code generation for included definitions if (included && !generateIncluded()) { return; } //no code generation for forward declarations (bug #539) if (!hasBody) { return; } try { String path = parser.out_dir + fileSeparator + pack_name.replace('.', fileSeparator); File dir = new File(path); if (!dir.exists()) { if (!dir.mkdirs()) org.jacorb.idl.parser.fatal_error ("Unable to create " + path, null); } printClass(dir); printFactory(dir); printHelper(dir); printHolder(dir); // print class files for exports definitions for (Iterator i = exports.iterator(); i.hasNext();) { ((IdlSymbol)i.next()).print(null); } } catch (IOException e) { org.jacorb.idl.parser.fatal_error ("I/O error writing " + javaName() + ": " + e, null); } } public String printWriteStatement(String var_name, String streamname) { // pass in null repository id to prevent CDROutputStream // to resolve the RMI repository ID return "((org.omg.CORBA_2_3.portable.OutputStream)" + streamname + ")" + ".write_value (" + var_name + ", (String)null);"; } public String printReadExpression(String streamname) { return "(" + javaName() + ")" + "((org.omg.CORBA_2_3.portable.InputStream)" + streamname + ")" + ".read_value (\"" + id() + "\")"; } public String printReadStatement(String var_name, String streamname) { return var_name + " = " + printReadExpression(streamname); } /** * Prints the abstract Java class to which this valuetype is mapped. */ private void printClass(File dir) throws IOException { File outfile = new File(dir, name + ".java"); // If we have a body (i.e. we've defined any pending_interface) and the 'more // recent check' is ok then write the file. if (hasBody && GlobalInputStream.isMoreRecentThan(outfile)) { PrintWriter out = new PrintWriter(new FileWriter(outfile)); if (pack_name.length() > 0) { out.println("package " + pack_name + ";" + Environment.NL); } printClassComment("valuetype", name, out); out.println("public abstract class " + name); // set up extends and implements clauses StringBuffer extendsBuffer = new StringBuffer("extends "); StringBuffer implementsBuffer = new StringBuffer("implements "); if (this.isCustomMarshalled()) implementsBuffer.append("org.omg.CORBA.portable.CustomValue"); else implementsBuffer.append("org.omg.CORBA.portable.StreamableValue"); if (inheritanceSpec != null) { boolean first = true; // go through ancestor value types Enumeration e = inheritanceSpec.getValueTypes(); if (e.hasMoreElements() || inheritanceSpec.truncatable != null) { if (e.hasMoreElements()) { ScopedName scopedName = (ScopedName)e.nextElement(); ConstrTypeSpec ts = unwindTypedefs(scopedName); //(ConstrTypeSpec)scopedName.resolvedTypeSpec().typeSpec(); // abstract base valuetypes are mapped to interfaces, so // we "implement" if (ts.c_type_spec instanceof ValueAbsDecl) { implementsBuffer.append(", " + ts.toString()); } else { // stateful base valuetypes are mapped to classes, so // we "extend" first = false; extendsBuffer.append(ts.toString()); } } for(; e.hasMoreElements();) { ScopedName scopedName = (ScopedName)e.nextElement(); ConstrTypeSpec ts = (ConstrTypeSpec)scopedName.resolvedTypeSpec().typeSpec(); // abstract base valuetypes are mapped to interfaces, so // we "implement" if (ts.c_type_spec instanceof ValueAbsDecl) { implementsBuffer.append(", " + scopedName.toString()); } else { // stateful base valuetypes are mapped to classes, so // we "extend" // // applied patch by Thomas Leineweber for bug #492 // if (first) { extendsBuffer.append(scopedName.toString()); first = false; } else { extendsBuffer.append(", " + scopedName.toString()); } } } // also check for the presence of a stateful base value type // that we can be truncated to if (inheritanceSpec.truncatable != null) { extendsBuffer.append ( (first ? "" : ", ") + inheritanceSpec.truncatable.scopedName ); } } // go through supported interfaces Enumeration enumeration = inheritanceSpec.getSupportedInterfaces(); if (enumeration.hasMoreElements()) { for(; enumeration.hasMoreElements();) { ScopedName sne = (ScopedName)enumeration.nextElement(); implementsBuffer.append (", " + sne); if (Interface.abstractInterfaces == null || !Interface.abstractInterfaces.contains (sne.toString())) { implementsBuffer.append ("Operations"); } } } } if (extendsBuffer.length() > 8) { hasStatefulBases = true; out.println("\t" + extendsBuffer.toString()); } out.println("\t" + implementsBuffer.toString()); out.println("{"); printSerialVersionUID(out); // collect and print repository ids that this value type can // truncated to. out.print("\tprivate String[] _truncatable_ids = {\"" + id() + "\""); StringBuffer sb = new StringBuffer(); if (inheritanceSpec != null) { Truncatable trunc = inheritanceSpec.truncatable; if (trunc != null) { sb.append(", \"" + trunc.getId() + "\""); ScopedName scopedName = trunc.scopedName; while(scopedName != null) { ValueDecl v = (ValueDecl)((ConstrTypeSpec)scopedName.resolvedTypeSpec()).c_type_spec; if (v.inheritanceSpec == null) { break; } Truncatable t = v.inheritanceSpec.truncatable; if (t != null) { sb.append(", \"" + t.getId() + "\""); scopedName = t.scopedName; } else { break; } } } } out.println(sb.toString() + "};"); for(Iterator i = stateMembers.v.iterator(); i.hasNext();) { ((StateMember)i.next()).print(out); out.println(); } for(Iterator i = operations.iterator(); i.hasNext();) { ((Operation)i.next()).printSignature(out, true); out.println(); } if (!this.isCustomMarshalled()) { printWriteMethod(out); printReadMethod(out); } out.println("\tpublic String[] _truncatable_ids()"); out.println("\t{"); out.println("\t\treturn _truncatable_ids;"); // FIXME out.println("\t}"); out.println("\tpublic org.omg.CORBA.TypeCode _type()"); out.println("\t{"); out.println("\t\treturn " + javaName() + "Helper.type();"); out.println("\t}"); out.println("}"); out.close(); } } /** * Prints the Factory interface for this valuetype if any * factories were defined. */ private void printFactory(File dir) throws IOException { if (factories.size() == 0) { return; } File outfile = new File(dir, name + "ValueFactory.java"); // If we have a body (i.e. we've defined any pending_interface) and the 'more // recent check' is ok then write the file. if (hasBody && GlobalInputStream.isMoreRecentThan(outfile)) { PrintWriter out = new PrintWriter(new FileWriter(outfile)); if (pack_name.length() > 0) { out.println("package " + pack_name + ";" + Environment.NL); } printClassComment("valuetype", name, out); out.println("public interface " + name + "ValueFactory"); out.println("\textends org.omg.CORBA.portable.ValueFactory"); out.println("{"); for(Iterator i = factories.iterator(); i.hasNext();) { ((InitDecl)i.next()).print(out, name); } out.println("}"); out.close(); } } /** * Prints the _write() method required by * org.omg.CORBA.portable.StreamableValue. */ private void printWriteMethod(PrintWriter out) { out.println("\tpublic void _write " + "(org.omg.CORBA.portable.OutputStream os)"); out.println("\t{"); if (hasStatefulBases) { out.println("\t\tsuper._write(os);"); } for(Iterator i = stateMembers.v.iterator(); i.hasNext();) { out.println("\t\t" + ((StateMember)i.next()).writeStatement("os")); } out.println("\t}" + Environment.NL); } /** * Prints the _read() method required by * org.omg.CORBA.portable.StreamableValue. */ private void printReadMethod(PrintWriter out) { out.println("\tpublic void _read " + "(final org.omg.CORBA.portable.InputStream os)"); out.println("\t{"); if (hasStatefulBases) { out.println("\t\tsuper._read(os);"); } for(Iterator i = stateMembers.v.iterator(); i.hasNext();) { out.println("\t\t" + ((StateMember)i.next()).readStatement("os")); } out.println("\t}" + Environment.NL); } private void printHelper(File dir) throws IOException { File outfile = new File(dir, name + "Helper.java"); // If we have a body (i.e. we've defined any pending_interface) and the 'more // recent check' is ok then write the file. if (hasBody && GlobalInputStream.isMoreRecentThan(outfile)) { PrintWriter out = new PrintWriter(new FileWriter(outfile)); if (pack_name.length() > 0) { out.println("package " + pack_name + ";" + Environment.NL); } printClassComment("valuetype", name, out); out.println("public abstract class " + name + "Helper"); out.println("{"); out.println("\tprivate volatile static org.omg.CORBA.TypeCode _type = null;"); // insert() / extract() out.println("\tpublic static void insert " + "(org.omg.CORBA.Any a, " + javaName() + " v)"); out.println("\t{"); out.println("\t\ta.insert_Value (v, v._type());"); out.println("\t}"); out.println("\tpublic static " + javaName() + " extract " + "(org.omg.CORBA.Any a)"); out.println("\t{"); out.println("\t\treturn (" + javaName() + ")a.extract_Value();"); out.println("\t}"); // type() / id() out.println("\tpublic static org.omg.CORBA.TypeCode type()"); out.println("\t{"); out.println("\t\tif (_type == null)"); out.println("\t\t{"); out.println("\t\t\tsynchronized(" + name + "Helper.class)"); out.println("\t\t\t{"); out.println("\t\t\t\tif (_type == null)"); out.println("\t\t\t\t{"); out.println("\t\t\t\t\t_type = " + getTypeCodeExpression() + ";"); out.println("\t\t\t\t}"); out.println("\t\t\t}"); out.println("\t\t}"); out.println("\t\treturn _type;"); out.println("\t}" + Environment.NL); out.println("\tpublic static String id()"); out.println("\t{"); out.println("\t\treturn \"" + id() + "\";"); out.println("\t}"); // read() / write() out.println("\tpublic static " + javaName() + " read " + "(org.omg.CORBA.portable.InputStream is)"); out.println("\t{"); out.println("\t\treturn (" + javaName() + ")((org.omg.CORBA_2_3.portable.InputStream)is).read_value (\"" + id() + "\");"); out.println("\t}"); out.println("\tpublic static void write " + "(org.omg.CORBA.portable.OutputStream os, " + javaName() + " val)"); out.println("\t{"); out.println("\t\t((org.omg.CORBA_2_3.portable.OutputStream)os)" + ".write_value (val, \"" + id() + "\");"); out.println("\t}"); // factory methods for (Iterator i = factories.iterator(); i.hasNext();) { InitDecl d = (InitDecl)i.next(); d.printHelperMethod (out, name); } out.println("}"); out.close(); } } private void printHolder(File dir) throws IOException { File outfile = new File(dir, name + "Holder.java"); // If we have a body (i.e. we've defined any pending_interface) and the 'more // recent check' is ok then write the file. if (hasBody && GlobalInputStream.isMoreRecentThan(outfile)) { PrintWriter out = new PrintWriter(new FileWriter(outfile)); if (pack_name.length() > 0) { out.println("package " + pack_name + ";" + Environment.NL); } printClassComment("valuetype", name, out); out.println("public" + parser.getFinalString() + " class " + name + "Holder"); out.println("\timplements org.omg.CORBA.portable.Streamable"); out.println("{"); out.println("\tpublic " + javaName() + " value;"); out.println("\tpublic " + name + "Holder () {}"); out.println("\tpublic " + name + "Holder (final " + javaName() + " initial)"); out.println("\t{"); out.println("\t\tvalue = initial;"); out.println("\t}"); out.println("\tpublic void _read " + "(final org.omg.CORBA.portable.InputStream is)"); out.println("\t{"); out.println("\t\tvalue = " + javaName() + "Helper.read (is);"); out.println("\t}"); out.println("\tpublic void _write " + "(final org.omg.CORBA.portable.OutputStream os)"); out.println("\t{"); out.println("\t\t" + javaName() + "Helper.write (os, value);"); out.println("\t}"); out.println("\tpublic org.omg.CORBA.TypeCode _type ()"); out.println("\t{"); out.println("\t\treturn value._type ();"); out.println("\t}"); out.println("}"); out.close(); } } public void printInsertIntoAny(PrintWriter ps, String anyname, String varname) { ps.println( "\t\t" + anyname + ".insert_Value(" + varname + ", "+ varname +"._type());"); } public void printExtractResult(PrintWriter ps, String resultname, String anyname, String resulttype) { ps.println("\t\t" + resultname + " = (" + resulttype + ")" + anyname + ".extract_Value();"); } public void accept(IDLTreeVisitor visitor) { visitor.visitValue(this); } }