blob: 26e6fb06394dbce6ba7a0a2f3cec0bdf1cec7eaa [file] [log] [blame]
/*
* Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* COMPONENT_NAME: idl.toJava
*
* ORIGINS: 27
*
* Licensed Materials - Property of IBM
* 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999
* RMI-IIOP v1.0
*
*/
package com.sun.tools.corba.se.idl.toJavaPortable;
// NOTES:
// -F46082.51<daz> Remove -stateful feature; javaStatefulName() obsolete.
// -D57067 <klr> suppress default init if an emit init explicitly specified.
// -D59071 <daz> Clone method entries when their content needs modification.
// -D59092 <klr> Valuetype supporting interfaces should implement interface.
// -D59418 <klr> Custom values implement org.omg.CORBA.CustomMarshal
// -D59418 <klr> Invert read/read_Value, write/write_Value for Simon
// -D60929 <klr> Update for RTF2.4 changes
// -D62018 <klr> write_value for value with value field x calls xHelper.write.
// -D62062 <klr> Add _write to value Helper to marshal state.
// write_value for value subclass calls parent._write
// -D61650<daz> Remove '\n' from generated strings; use println()'s.
import java.io.File;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import com.sun.tools.corba.se.idl.GenFileStream;
import com.sun.tools.corba.se.idl.InterfaceEntry;
import com.sun.tools.corba.se.idl.SymtabEntry;
import com.sun.tools.corba.se.idl.TypedefEntry;
import com.sun.tools.corba.se.idl.ValueEntry;
import com.sun.tools.corba.se.idl.ValueBoxEntry;
import com.sun.tools.corba.se.idl.InterfaceState;
import com.sun.tools.corba.se.idl.MethodEntry;
import com.sun.tools.corba.se.idl.PrimitiveEntry;
import com.sun.tools.corba.se.idl.SequenceEntry;
import com.sun.tools.corba.se.idl.StringEntry;
import com.sun.tools.corba.se.idl.StructEntry;
/**
*
**/
public class ValueGen implements com.sun.tools.corba.se.idl.ValueGen, JavaGenerator
{
/**
* Public zero-argument constructor.
**/
public ValueGen ()
{
} // ctor
/**
*
**/
public void generate (Hashtable symbolTable, ValueEntry v, PrintWriter str)
{
this.symbolTable = symbolTable;
this.v = v;
init ();
openStream ();
if (stream == null)
return;
generateTie ();
generateHelper ();
generateHolder ();
writeHeading ();
writeBody ();
writeClosing ();
closeStream ();
} // generate
/**
* Initialize members unique to this generator.
**/
protected void init ()
{
emit = ((Arguments)Compile.compiler.arguments).emit;
factories = (Factories)Compile.compiler.factories ();
} // init
/**
*
**/
protected void openStream ()
{
stream = Util.stream (v, ".java");
} // openStream
/**
* Generate a Tie class only when the user specifies the TIE option
* and the valuetype does support an interface.
**/
protected void generateTie ()
{
boolean tie = ((Arguments)Compile.compiler.arguments).TIEServer;
if (v.supports ().size () > 0 && tie)
{
Factories factories = (Factories)Compile.compiler.factories ();
factories.skeleton ().generate (symbolTable, v);
}
} // generateTie
/**
*
**/
protected void generateHelper ()
{
((Factories)Compile.compiler.factories ()).helper ().generate (symbolTable, v);
} // generateHelper
/**
*
**/
protected void generateHolder ()
{
((Factories)Compile.compiler.factories ()).holder ().generate (symbolTable, v);
} // generateHolder
/**
*
**/
protected void writeHeading ()
{
Util.writePackage (stream, v);
Util.writeProlog (stream, ((GenFileStream)stream).name ());
if (v.comment () != null)
v.comment ().generate ("", stream);
if (v.isAbstract ())
{
writeAbstract ();
return;
}
else
stream.print ("public class " + v.name ());
// There should always be at least one parent: ValueBase
SymtabEntry parent = (SymtabEntry) v.derivedFrom ().elementAt (0);
// If parent is ValueBase, it's mapped to java.io.Serializable
String parentName = Util.javaName (parent);
boolean impl = false;
if (parentName.equals ("java.io.Serializable"))
{
// stream.print (" implements org.omg.CORBA.portable.ValueBase, org.omg.CORBA.portable.Streamable");
stream.print (" implements org.omg.CORBA.portable.ValueBase"); // <d60929>
impl = true;
}
else if ( !((ValueEntry)parent).isAbstract ())
stream.print (" extends " + parentName);
// if inheriting from abstract values
for (int i = 0; i < v.derivedFrom ().size (); i++) {
parent = (SymtabEntry) v.derivedFrom ().elementAt (i);
if ( ((ValueEntry)parent).isAbstract ())
{
if (!impl)
{
stream.print (" implements ");
impl = true;
}
else
stream.print (", ");
stream.print (Util.javaName (parent));
}
}
// <d59092-klr> Valuetype supporting interface implement Operations interface
// for supported IDL interface
if (((ValueEntry)v).supports ().size () > 0) {
if (!impl)
{
stream.print (" implements ");
impl = true;
}
else
stream.print (", ");
InterfaceEntry s =(InterfaceEntry)((ValueEntry)v).supports().elementAt(0);
// abstract supported classes don't have "Operations"
if (s.isAbstract ())
stream.print (Util.javaName (s));
else
stream.print (Util.javaName (s) + "Operations");
}
// <d59418> Custom valuetypes implement org.omg.CORBA.CustomMarshal.
if ( ((ValueEntry)v).isCustom ()) {
if (!impl)
{
stream.print (" implements ");
impl = true;
}
else
stream.print (", ");
stream.print ("org.omg.CORBA.CustomMarshal ");
}
stream.println ();
stream.println ("{");
} // writeHeading
/**
*
**/
protected void writeBody ()
{
writeMembers ();
writeInitializers ();
writeConstructor (); // <d57067>
writeTruncatable (); // <d60929>
writeMethods ();
} // writeBody
/**
*
**/
protected void writeClosing ()
{
if (v.isAbstract ())
stream.println ("} // interface " + v.name ());
else
stream.println ("} // class " + v.name ());
} // writeClosing
/**
*
**/
protected void closeStream ()
{
stream.close ();
} // closeStream
/**
*
**/
protected void writeConstructor ()
{
// Per Simon, 9/3/98, emit a protected default constructor
if (!v.isAbstract () && !explicitDefaultInit) { // <d57067 - klr>
stream.println (" protected " + v.name () + " () {}");
stream.println ();
}
} // writeConstructor
/**
*
**/
protected void writeTruncatable () // <d60929>
{
// Per Simon, 4/6/98, emit _truncatable_ids()
if (!v.isAbstract ()) {
stream.println (" public String[] _truncatable_ids() {");
stream.println (" return " + Util.helperName(v, true) + ".get_instance().get_truncatable_base_ids();"); // <d61056>
stream.println (" }");
stream.println ();
}
} // writeTruncatable
/**
*
**/
protected void writeMembers ()
{
// if the value type contains no data members, a null return is expected
if (v.state () == null)
return;
for (int i = 0; i < v.state ().size (); i ++)
{
InterfaceState member = (InterfaceState) v.state ().elementAt (i);
SymtabEntry entry = (SymtabEntry) member.entry;
Util.fillInfo (entry);
if (entry.comment () != null)
entry.comment ().generate (" ", stream);
String modifier = " ";
if (member.modifier == InterfaceState.Public)
modifier = " public ";
Util.writeInitializer (modifier, entry.name (), "", entry, stream);
}
} // writeMembers
/**
*
**/
protected void writeInitializers ()
{
Vector init = v.initializers ();
if (init != null)
{
stream.println ();
for (int i = 0; i < init.size (); i++)
{
MethodEntry element = (MethodEntry) init.elementAt (i);
element.valueMethod (true);
((MethodGen) element.generator ()). interfaceMethod (symbolTable, element, stream);
if (element.parameters ().isEmpty ()) // <d57067-klr>
explicitDefaultInit = true;
}
}
} // writeInitializers
/**
*
**/
protected void writeMethods ()
{
// contained vector contains methods, attributes, const, enums, exceptions,
// structs, unions, or typedefs that are declared inside the value object.
// State members of the nested types are also included in this vector.
// Thus, if the declaration of a constructed type is nested in the decl.
// of a state member, e.g struct x {boolean b;} memberx;
// the generation of the nested type must be handled here.
Enumeration e = v.contained ().elements ();
while (e.hasMoreElements ())
{
SymtabEntry contained = (SymtabEntry)e.nextElement ();
if (contained instanceof MethodEntry)
{
MethodEntry element = (MethodEntry)contained;
((MethodGen)element.generator ()).interfaceMethod (symbolTable, element, stream);
}
else
{
// Generate the type referenced by the typedef.
if (contained instanceof TypedefEntry)
contained.type ().generate (symbolTable, stream);
// Note that we also need to generate the typedef itself if
// contained is a typedef.
contained.generate (symbolTable, stream);
}
}
// Abstract values are mapped to interfaces. There is no need to generate
// the bindings for inheriting methods in case of inheritance from other
// abstract values or supporting interface
if (v.isAbstract ())
return;
// workaround: if the value type doesnot support any interfaces, a null
// return is expected instead of an empty vector
// if supporting an interfaces, generate bindings for inheriting methods
if (v.supports ().size () > 0)
{
InterfaceEntry intf = (InterfaceEntry) v.supports ().elementAt (0);
Enumeration el = intf.allMethods ().elements ();
while (el.hasMoreElements ())
{
MethodEntry m = (MethodEntry) el.nextElement ();
// <d59071> Don't alter the symbol table/emit list elements!
//m.container (v);
//((MethodGen)m.generator ()).interfaceMethod (symbolTable, m, stream);
MethodEntry mClone = (MethodEntry)m.clone ();
mClone.container (v);
((MethodGen)mClone.generator ()).interfaceMethod (symbolTable, mClone, stream);
}
}
// if inheriting from abstract values, generating bindings for all
// inheriting methods
for (int i = 0; i < v.derivedFrom ().size (); i++) {
ValueEntry parentValue = (ValueEntry) v.derivedFrom ().elementAt (i);
if (parentValue.isAbstract ())
{
Enumeration el = parentValue.allMethods ().elements ();
while (el.hasMoreElements ())
{
MethodEntry m = (MethodEntry) el.nextElement ();
// <d59071> Don't alter the symbol table/emit list elements!
//m.container (v);
//((MethodGen)m.generator ()).interfaceMethod (symbolTable, m, stream);
MethodEntry mClone = (MethodEntry)m.clone ();
mClone.container (v);
((MethodGen)mClone.generator ()).interfaceMethod (symbolTable, mClone, stream);
}
}
}
//writeStreamableMethods ();
} // writeMethods
/**
*
**/
protected void writeStreamableMethods ()
{
stream.println (" public void _read (org.omg.CORBA.portable.InputStream istream)");
stream.println (" {");
read (0, " ", "this", v, stream);
stream.println (" }");
stream.println ();
stream.println (" public void _write (org.omg.CORBA.portable.OutputStream ostream)");
stream.println (" {");
write (0, " ", "this", v, stream);
stream.println (" }");
stream.println ();
stream.println (" public org.omg.CORBA.TypeCode _type ()");
stream.println (" {");
stream.println (" return " + Util.helperName (v, false) + ".type ();"); // <d61056>
stream.println (" }");
} // writeStreamableMethods
///////////////
// From JavaGenerator
public int helperType (int index, String indent, TCOffsets tcoffsets, String name, SymtabEntry entry, PrintWriter stream)
{
ValueEntry vt = (ValueEntry) entry;
Vector state = vt.state ();
int noOfMembers = state == null ? 0 : state.size ();
String members = "_members" + index++;
String tcOfMembers = "_tcOf" + members;
stream.println (indent + "org.omg.CORBA.ValueMember[] "
+ members + " = new org.omg.CORBA.ValueMember["
+ noOfMembers
+ "];");
stream.println (indent + "org.omg.CORBA.TypeCode " + tcOfMembers + " = null;");
//stream.println (""); // <d61650>
String definedInrepId = "_id";
String repId, version;
for (int k=0; k<noOfMembers; k++)
{
InterfaceState valueMember = (InterfaceState)state.elementAt (k);
TypedefEntry member = (TypedefEntry)valueMember.entry;
SymtabEntry mType = Util.typeOf (member);
if (hasRepId (member))
{
repId = Util.helperName (mType, true) + ".id ()"; // <d61056>
if (mType instanceof ValueEntry || mType instanceof ValueBoxEntry)
// OBV spec is silent on defining VersionSpec for valuetype RepIds
version = "\"\"";
else
{
String id = mType.repositoryID ().ID ();
version = '"' + id.substring (id.lastIndexOf (':')+1) + '"';
}
}
else
{
repId = "\"\"";
version = "\"\"";
}
// Get TypeCode for valuetype member and store it var. name given by tcOfMembers
stream.println (indent + "// ValueMember instance for " + member.name ());
index = ((JavaGenerator)member.generator ()).type (index, indent, tcoffsets, tcOfMembers, member, stream);
stream.println (indent + members + "[" + k + "] = new org.omg.CORBA.ValueMember (" // <d61650>
+ '"' + member.name () + "\", "); // name
stream.println (indent + " " + repId + ", "); // id
stream.println (indent + " " + definedInrepId + ", "); // defined_in
stream.println (indent + " " + version + ", "); // version
stream.println (indent + " " + tcOfMembers + ", "); // type
stream.println (indent + " " + "null, "); // type_def
stream.println (indent + " " + "org.omg.CORBA." +
(valueMember.modifier == InterfaceState.Public ?
"PUBLIC_MEMBER" : "PRIVATE_MEMBER") + ".value" + ");"); // access
} // end for
stream.println (indent + name + " = org.omg.CORBA.ORB.init ().create_value_tc ("
+ "_id, "
+ '"' + entry.name () + "\", "
+ getValueModifier (vt) + ", "
+ getConcreteBaseTypeCode (vt) + ", "
+ members
+ ");");
return index;
} // helperType
public int type (int index, String indent, TCOffsets tcoffsets, String name, SymtabEntry entry, PrintWriter stream) {
stream.println (indent + name + " = " + Util.helperName (entry, true) + ".type ();"); // <d61056>
return index;
} // type
// Check for types which don't have a Repository ID: primitive,
// string, arrays and sequences.
private static boolean hasRepId (SymtabEntry member)
{
SymtabEntry mType = Util.typeOf (member);
return !( mType instanceof PrimitiveEntry ||
mType instanceof StringEntry ||
( mType instanceof TypedefEntry &&
!(((TypedefEntry)mType).arrayInfo ().isEmpty ()) ) ||
( mType instanceof TypedefEntry && member.type () instanceof SequenceEntry) );
} // hasRepId
private static String getValueModifier (ValueEntry vt)
{
String mod = "NONE";
if (vt.isCustom ())
mod = "CUSTOM";
else if (vt.isAbstract ())
mod = "ABSTRACT";
else if (vt.isSafe ())
mod = "TRUNCATABLE";
return "org.omg.CORBA.VM_" + mod + ".value";
} // getValueModifier
private static String getConcreteBaseTypeCode (ValueEntry vt)
{
Vector v = vt.derivedFrom ();
if (!vt.isAbstract ())
{
SymtabEntry base = (SymtabEntry)vt.derivedFrom ().elementAt (0);
if (!"ValueBase".equals (base.name ()))
return Util.helperName (base, true) + ".type ()"; // <d61056>
}
return "null";
} // getConcreteBaseTypeCode
public void helperRead (String entryName, SymtabEntry entry, PrintWriter stream)
{
// <d59418 - KLR> per Simon, make "static" read call istream.read_value.
// put real marshalling code in read_value.
if (((ValueEntry)entry).isAbstract ())
{
stream.println (" throw new org.omg.CORBA.BAD_OPERATION (\"abstract value cannot be instantiated\");");
}
else
{
stream.println (" return (" + entryName +") ((org.omg.CORBA_2_3.portable.InputStream) istream).read_value (get_instance());"); // <d60929>
}
stream.println (" }");
stream.println ();
// done with "read", now do "read_value with real marshalling code.
stream.println (" public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream istream)"); // <d60929>
stream.println (" {");
// per Simon, 3/3/99, read_value for custom values throws an exception
if (((ValueEntry)entry).isAbstract ())
{
stream.println (" throw new org.omg.CORBA.BAD_OPERATION (\"abstract value cannot be instantiated\");");
}
else
if (((ValueEntry)entry).isCustom ())
{
stream.println (" throw new org.omg.CORBA.BAD_OPERATION (\"custom values should use unmarshal()\");");
}
else
{
stream.println (" " + entryName + " value = new " + entryName + " ();");
read (0, " ", "value", entry, stream);
stream.println (" return value;");
}
stream.println (" }");
stream.println ();
// End of normal read method
// Per Simon, 8/26/98 - Value helpers get an additional overloaded
// read method where the value is passed in instead of "new'd" up. This is
// used for reading parent value state.
// Per Simon, 3/3/99 - Don't change this "read" for custom marshalling
stream.println (" public static void read (org.omg.CORBA.portable.InputStream istream, " + entryName + " value)");
stream.println (" {");
read (0, " ", "value", entry, stream);
} // helperRead
public int read (int index, String indent, String name, SymtabEntry entry, PrintWriter stream)
{
// First do the state members from concrete parent hierarchy
Vector vParents = ((ValueEntry) entry).derivedFrom ();
if (vParents != null && vParents.size() != 0)
{
ValueEntry parent = (ValueEntry) vParents.elementAt (0);
if (parent == null)
return index;
// Per Simon, 4/6/99 - call parent read. <d60929>
if (! Util.javaQualifiedName(parent).equals ("java.io.Serializable")) // <d60929>
stream.println(indent + Util.helperName (parent, true) + ".read (istream, value);"); // <d60929> // <d61056>
}
Vector vMembers = ((ValueEntry) entry).state ();
int noOfMembers = vMembers == null ? 0 : vMembers.size ();
for (int k = 0; k < noOfMembers; k++)
{
TypedefEntry member = (TypedefEntry)((InterfaceState)vMembers.elementAt (k)).entry;
String memberName = member.name ();
SymtabEntry mType = member.type ();
if (mType instanceof PrimitiveEntry ||
mType instanceof TypedefEntry ||
mType instanceof SequenceEntry ||
mType instanceof StringEntry ||
!member.arrayInfo ().isEmpty ())
index = ((JavaGenerator)member.generator ()).read (index, indent, name + '.' + memberName, member, stream);
else if (mType instanceof ValueEntry)
{
String returnType = Util.javaQualifiedName (mType);
if (mType instanceof ValueBoxEntry)
// <f46082.51> Remove -stateful.
//returnType = Util.javaStatefulName (mType);
returnType = Util.javaName (mType);
stream.println (" " + name + '.' + memberName + " = (" + returnType +
") ((org.omg.CORBA_2_3.portable.InputStream)istream).read_value (" + Util.helperName (mType, true) + // <d61056>
".get_instance ());"); // <d61056>
}
else
stream.println (indent + name + '.' + memberName + " = " +
Util.helperName (mType, true) + ".read (istream);"); // <d61056>
}
return index;
} // read
public void helperWrite (SymtabEntry entry, PrintWriter stream)
{
// <d59418 - KLR> per Simon, make "static" write call istream.write_value.
// put real marshalling code in write_value.
stream.println (" ((org.omg.CORBA_2_3.portable.OutputStream) ostream).write_value (value, get_instance());"); // <d60929>
stream.println (" }");
stream.println ();
// <d62062>
// per Simon, 4/27/99, add static _write that marshals the state of this
// value for non-custom valuetypes
if (!((ValueEntry)entry).isCustom ())
{
stream.println (" public static void _write (org.omg.CORBA.portable.OutputStream ostream, " + Util.javaName (entry) + " value)");
stream.println (" {");
write (0, " ", "value", entry, stream);
stream.println (" }");
stream.println ();
}
// done with "_write", now do "write_value
stream.println (" public void write_value (org.omg.CORBA.portable.OutputStream ostream, java.io.Serializable obj)"); // <d60929>
stream.println (" {");
// per Simon, 3/3/99, write_value for custom values throws an exception
if (((ValueEntry)entry).isCustom ())
{
stream.println (" throw new org.omg.CORBA.BAD_OPERATION (\"custom values should use marshal()\");");
}
else {
String entryName = Util.javaName(entry);
stream.println (" _write (ostream, (" + entryName + ") obj);"); // <d62062>
// write (0, " ", "value", entry, stream); <d62062>
}
} // helperWrite
public int write (int index, String indent, String name, SymtabEntry entry, PrintWriter stream)
{
// First do the state members from concrete parent hierarchy
Vector vParents = ((ValueEntry)entry).derivedFrom ();
if (vParents != null && vParents.size () != 0)
{
ValueEntry parent = (ValueEntry)vParents.elementAt (0);
if (parent == null)
return index;
// Per Simon, 4/06/99 - call parent write. <d60929>
// Per Simon, 4/27/99 - call parent _write. <d62062>
if (! Util.javaQualifiedName(parent).equals ("java.io.Serializable")) // <d60929>
stream.println(indent + Util.helperName (parent, true) + "._write (ostream, value);"); // <d60929> <d61056> <d62062>
}
Vector vMembers = ((ValueEntry) entry ).state ();
int noOfMembers = vMembers == null ? 0 : vMembers.size ();
for (int k = 0; k < noOfMembers; k++)
{
TypedefEntry member = (TypedefEntry)((InterfaceState)vMembers.elementAt (k)).entry;
String memberName = member.name ();
SymtabEntry mType = member.type ();
if (mType instanceof PrimitiveEntry ||
mType instanceof TypedefEntry ||
mType instanceof SequenceEntry ||
mType instanceof StringEntry ||
!member.arrayInfo ().isEmpty ())
index = ((JavaGenerator)member.generator ()).write (index, indent, name + '.' + memberName, member, stream);
else
stream.println (indent + Util.helperName (mType, true) + // <d61056>
".write (ostream, " + name + '.' + memberName + ");");
}
return index;
} // write
/**
*
**/
protected void writeAbstract ()
{
stream.print ("public interface " + v.name ());
// workaround: if the abstract value type does not have any parent, a vector
// containing ValueBase should be returned instead of an empty vector
if (v.derivedFrom ().size () == 0)
stream.print (" extends org.omg.CORBA.portable.ValueBase"); // <d60929>
else
{
SymtabEntry parent;
// list the values the abstract value type inherits
for (int i = 0; i < v.derivedFrom ().size (); i++)
{
if (i == 0)
stream.print (" extends ");
else
stream.print (", ");
parent = (SymtabEntry) v.derivedFrom ().elementAt (i);
stream.print (Util.javaName (parent));
}
}
// list the interface the abstract value type supports
if (v.supports ().size () > 0)
{
stream.print (", ");
SymtabEntry intf = (SymtabEntry) v.supports ().elementAt (0);
stream.print (Util.javaName (intf));
}
stream.println ();
stream.println ("{");
}
protected int emit = 0;
protected Factories factories = null;
protected Hashtable symbolTable = null;
protected ValueEntry v = null;
protected PrintWriter stream = null;
protected boolean explicitDefaultInit = false; // <d57067 - klr>
} // class ValueGen