/*
* 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.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
/**
* IDL sequences.
*
*
* @author Gerald Brose
*/
public class SequenceType
extends VectorType
{
private boolean written = false;
/** used to generate unique name vor local variables */
private static int idxNum = 0;
/** markers for recursive sequences */
private boolean recursive = false;
public ConstExpr max = null;
int length = 0;
public SequenceType(int num)
{
super(num);
name = null;
typedefd = false;
}
public Object clone()
{
SequenceType copy = new SequenceType(IdlSymbol.new_num());
copy.type_spec = this.type_spec;
copy.max = this.max;
copy.length = this.length;
copy.name = this.name;
copy.pack_name = this.pack_name;
copy.included = this.included;
copy.typedefd = this.typedefd;
copy.recursive = this.recursive;
copy.set_token(this.get_token());
copy.setEnclosingSymbol(this.getEnclosingSymbol());
return copy;
}
public void setEnclosingSymbol(IdlSymbol symbol)
{
if (enclosing_symbol != null && enclosing_symbol != symbol)
{
throw new RuntimeException("Compiler Error: trying to reassign container for " + name);
}
enclosing_symbol = symbol;
}
/**
* since the sequence type's name depends on a declarator
* given in the typedef, the name varilabe has to be set explicitly
* by the TypeDef object before this sequence type can
* be used.
*/
public TypeSpec typeSpec()
{
return this;
}
public void setPackage(String pkg)
{
pkg = parser.pack_replace(pkg);
if (pack_name.length() > 0)
{
pack_name = pkg + "." + pack_name;
}
else
{
pack_name = pkg;
}
type_spec.setPackage(pkg);
if (max != null)
{
max.setPackage(pkg);
}
}
/**
*/
public int length()
{
return length;
}
void setRecursive()
{
if (parser.logger.isLoggable(Level.WARNING))
{
parser.logger.log(Level.WARNING, "Sequence " + typeName +
" set recursive ------- this: " + this);
}
recursive = true;
}
/**
* @return a string for an expression of type TypeCode that describes this type
*/
public String getTypeCodeExpression()
{
return getTypeCodeExpression(new HashSet());
}
public String getTypeCodeExpression(Set knownTypes)
{
if (parser.logger.isLoggable(Level.ALL))
{
parser.logger.log(Level.ALL, "Sequence getTypeCodeExpression " + name);
}
//If type is already known, create recursive typeCode
//TODO: Check
if (knownTypes.contains(this))
{
return "org.omg.CORBA.ORB.init().create_recursive_tc(\"" +
elementTypeSpec().id() + "\")";
}
knownTypes.add(this);
String originalType = null;
if (recursive)
{
originalType = "org.omg.CORBA.ORB.init().create_sequence_tc(" +
length + ", org.omg.CORBA.ORB.init().create_recursive_tc(\"" +
elementTypeSpec().id() + "\"))";
}
else
{
originalType = "org.omg.CORBA.ORB.init().create_sequence_tc(" +
length + ", " + elementTypeExpression(knownTypes) + ")";
}
return originalType;
}
public static int getNumber()
{
return idxNum++;
}
/**
* We have to distinguish between sequence types that have been
* explicitly declared as types with a typedef and those that
* are declared as anonymous types in structs or unions. In
* the latter case, we have to generate marshalling code in-line
* because there are no helpers for anonymous types
*/
public String printReadStatement(String var_name, String streamname)
{
if (parser.logger.isLoggable(Level.ALL))
{
parser.logger.log(Level.ALL, "Sequence printReadStatement for " + typeName());
}
StringBuffer buffer = new StringBuffer();
String type = typeName();
String lgt = "_l" + var_name.replace('.', '_');
// if [i] is part of the name, trim that off
if (lgt.indexOf('[') > 0)
{
lgt = lgt.substring(0, lgt.indexOf('[')) + "_";
}
// make local variable name unique
lgt = lgt + getNumber();
buffer.append("int " + lgt + " = " + streamname + ".read_long();" + Environment.NL);
if (length != 0)
{
buffer.append("\t\tif (" + lgt + " > " + length + ")" + Environment.NL);
buffer.append("\t\t\tthrow new org.omg.CORBA.MARSHAL(\"Sequence length incorrect!\");" + Environment.NL);
}
buffer.append("\t\ttry" + Environment.NL + "\t\t{" + Environment.NL );
buffer.append("\t\t\t int x = " + streamname + ".available();" + Environment.NL );
buffer.append("\t\t\t if ( x > 0 && " + lgt + " > x )" + Environment.NL );
buffer.append("\t\t\t\t{" + Environment.NL );
buffer.append("\t\t\t\t\tthrow new org.omg.CORBA.MARSHAL(\"Sequence length too large. Only \" + x + \" available and trying to assign \" + "
+ lgt + ");" + Environment.NL);
buffer.append("\t\t\t\t}" + Environment.NL );
buffer.append("\t\t}" + Environment.NL + "\t\tcatch (java.io.IOException e)" + Environment.NL
+ "\t\t{" + Environment.NL + "\t\t}" + Environment.NL);
buffer.append("\t\t" + var_name + " = new " + type.substring(0, type.indexOf('[')) +
"[" + lgt + "]" + type.substring(type.indexOf(']') + 1) + ";" + Environment.NL);
TypeSpec elemType = elementTypeSpec();
while (elemType instanceof AliasTypeSpec)
{
//get real type
elemType = ((AliasTypeSpec) elemType).originalType();
}
if (elemType instanceof BaseType &&
!(elemType instanceof AnyType))
{
String _tmp = elemType.printReadExpression(streamname);
buffer.append("\t\t");
buffer.append(_tmp.substring(0, _tmp.indexOf('(')));
buffer.append("_array(");
buffer.append(var_name);
buffer.append(",0,");
buffer.append(lgt);
buffer.append(");");
}
else
{
char idx_variable = 'i';
String indent = "";
if (var_name.endsWith("]"))
{
idx_variable = (char)(var_name.charAt(var_name.length() - 2) + 1);
indent = " ";
}
buffer.append("\t\t" + indent + "for (int " + idx_variable + "=0;"
+ idx_variable + "<" + var_name + ".length;" + idx_variable
+ "++)" + Environment.NL + "\t\t" + indent + "{" + Environment.NL);
buffer.append("\t\t\t" + indent +
elementTypeSpec().printReadStatement(var_name +
"[" + idx_variable + "]",
streamname)
+ Environment.NL);
buffer.append("\t\t" + indent + "}" + Environment.NL);
}
return buffer.toString();
}
public String printWriteStatement(String var_name, String streamname)
{
StringBuffer buffer = new StringBuffer();
if (length != 0)
{
buffer.append("\t\tif (" + var_name + ".length > " + length + ")" + Environment.NL);
buffer.append("\t\t\tthrow new org.omg.CORBA.MARSHAL(\"Incorrect sequence length\");");
}
buffer.append(Environment.NL);
buffer.append("\t\t" + streamname + ".write_long(" + var_name + ".length);" + Environment.NL);
TypeSpec elemType = elementTypeSpec();
while (elemType instanceof AliasTypeSpec)
{
//get real type
elemType = ((AliasTypeSpec) elemType).originalType();
}
if (elemType instanceof BaseType &&
!(elemType instanceof AnyType))
{
String _tmp = elemType.printWriteStatement(var_name, streamname);
buffer.append("\t\t");
buffer.append(_tmp.substring(0, _tmp.indexOf('(')));
buffer.append("_array(");
buffer.append(var_name);
buffer.append(",0,");
buffer.append(var_name);
buffer.append(".length);");
}
else
{
char idx_variable = 'i';
String indent = "";
if (var_name.endsWith("]"))
{
idx_variable = (char)(var_name.charAt(var_name.length() - 2) + 1);
indent = " ";
}
buffer.append("\t\t" + indent + "for (int " + idx_variable + "=0; "
+ idx_variable + "<" + var_name + ".length;"
+ idx_variable + "++)" + Environment.NL
+ "\t\t" + indent + "{" + Environment.NL);
buffer.append("\t\t\t" + indent +
elementTypeSpec().printWriteStatement(var_name
+ "[" + idx_variable + "]",
streamname) + Environment.NL);
buffer.append("\t\t" + indent + "}" + Environment.NL);
}
return buffer.toString();
}
public String holderName()
{
if (!typedefd)
{
throw new RuntimeException("Compiler Error: should not be called (helpername on not typedef'd SequenceType " + name + ")");
}
String name = full_name();
if (pack_name.length() > 0)
{
name = getFullName(name);
}
return name + "Holder";
}
public String helperName()
{
if (!typedefd)
{
throw new RuntimeException("Compiler Error: should not be called (helperName() on not typedef'd SequenceType)");
}
String name = full_name();
if (pack_name.length() > 0)
{
name = getFullName(name);
}
return name + "Helper";
}
public String className()
{
String fullName = full_name();
String cName;
if (fullName.indexOf('.') > 0)
{
pack_name = fullName.substring(0, fullName.lastIndexOf('.'));
cName = fullName.substring(fullName.lastIndexOf('.') + 1);
}
else
{
pack_name = "";
cName = fullName;
}
return cName;
}
/**
* The parsing phase.
*/
public void parse()
{
if (max != null)
{
max.parse();
length = max.pos_int_const();
}
if (type_spec.typeSpec() instanceof ScopedName)
{
TypeSpec typeSpec =
((ScopedName)type_spec.typeSpec()).resolvedTypeSpec();
if (typeSpec != null)
{
type_spec = typeSpec;
}
if (type_spec instanceof AliasTypeSpec)
{
addImportedAlias(type_spec.full_name());
}
else
{
addImportedName(type_spec.typeName());
}
addImportedName(type_spec.typeSpec().typeName());
}
try
{
NameTable.define(full_name(), IDLTypes.TYPE);
}
catch (NameAlreadyDefined n)
{
// ignore, sequence types can be defined a number
// of times under different names
}
}
public String full_name()
{
if (name == null)
{
return "<" + pack_name + ".anon>";
}
if (pack_name.length() > 0)
{
return ScopedName.unPseudoName(pack_name + "." + name);
}
return ScopedName.unPseudoName(name);
}
private void printHolderClass(String className, PrintWriter out)
{
if (!pack_name.equals(""))
{
out.println("package " + pack_name + ";" + Environment.NL);
}
String type = typeName();
printImport(out);
printClassComment("sequence", className, out);
out.println("public" + parser.getFinalString() + " class " + className + "Holder");
out.println("\timplements org.omg.CORBA.portable.Streamable");
out.println("{");
out.println("\tpublic " + type + " value;");
out.println("\tpublic " + className + "Holder ()");
out.println("\t{");
out.println("\t}");
out.println("\tpublic " + className + "Holder (final " + type + " initial)"
+ Environment.NL + "\t{");
out.println("\t\tvalue = initial;");
out.println("\t}");
out.println("\tpublic org.omg.CORBA.TypeCode _type ()");
out.println("\t{");
out.println("\t\treturn " + className + "Helper.type ();");
out.println("\t}");
out.println("\tpublic void _read (final org.omg.CORBA.portable.InputStream _in)");
out.println("\t{");
out.println("\t\tvalue = " + className + "Helper.read (_in);");
out.println("\t}");
out.println("\tpublic void _write (final org.omg.CORBA.portable.OutputStream _out)");
out.println("\t{");
out.println("\t\t" + className + "Helper.write (_out,value);");
out.println("\t}");
out.println("}");
}
private void printHelperClass(String className, PrintWriter out)
{
if (!pack_name.equals(""))
{
out.println("package " + pack_name + ";");
}
String type = typeName();
printImport(out);
printClassComment("sequence", className, out);
out.println("public abstract class " + className + "Helper");
out.println("{");
out.println("\tprivate static org.omg.CORBA.TypeCode _type = " +
getTypeCodeExpression() + ";");
TypeSpec.printHelperClassMethods(out, type);
printIdMethod(out); // from IdlSymbol
/** read */
out.println("\tpublic static " + type +
" read (final org.omg.CORBA.portable.InputStream in)");
out.println("\t{");
out.println("\t\tint l = in.read_long();");
if (length != 0)
{
out.println("\t\tif (l > " + length + ")");
out.println("\t\t\tthrow new org.omg.CORBA.MARSHAL();");
}
out.println("\t\t" + type + " result = new " +
type.substring(0, type.indexOf('[')) + "[l]" +
type.substring(type.indexOf(']') + 1) + ";");
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printReadExpression("in");
out.println("\t\t" + _tmp.substring(0, _tmp.indexOf('(')) +
"_array(result,0,result.length);");
}
else
{
out.println("\t\tfor (int i = 0; i < l; i++)");
out.println("\t\t{");
out.println("\t\t\t" + elementTypeSpec().printReadStatement("result[i]", "in"));
out.println("\t\t}");
}
out.println("\t\treturn result;");
out.println("\t}");
/* write */
out.println("\tpublic static void write (final org.omg.CORBA.portable.OutputStream out, "
+ "final " + type + " s)");
out.println("\t{");
if (length != 0)
{
out.println("\t\tif (s.length > " + length + ")");
out.println("\t\t\tthrow new org.omg.CORBA.MARSHAL();");
}
out.println("\t\tout.write_long(s.length);");
if (elementTypeSpec() instanceof BaseType &&
!(elementTypeSpec() instanceof AnyType))
{
String _tmp = elementTypeSpec().printWriteStatement("s", "out");
out.println(_tmp.substring(0, _tmp.indexOf('(')) + "_array(s,0,s.length);");
}
else
{
out.println("\t\tfor (int i = 0; i < s.length; i++)");
out.println("\t\t\t" + elementTypeSpec().printWriteStatement("s[i]", "out"));
}
out.println("\t}");
out.println("}");
}
public void print(PrintWriter out)
{
try
{
// only generate class files for explicitly
// defined sequence types, i.e. for typedef'd ones
if ((!written) && typedefd)
{
// write holder file
String fullName = full_name();
String className;
if (fullName.indexOf('.') > 0)
{
pack_name = fullName.substring(0, fullName.lastIndexOf('.'));
className = fullName.substring(fullName.lastIndexOf('.') + 1);
}
else
{
pack_name = "";
className = fullName;
}
String path = parser.out_dir + fileSeparator +
pack_name.replace('.', fileSeparator);
File dir = new File(path);
if (!dir.exists() && !dir.mkdirs())
{
org.jacorb.idl.parser.fatal_error("Unable to create " +
path, null);
}
String fname = className + "Holder.java";
File file = new File(dir, fname);
if (GlobalInputStream.isMoreRecentThan(file))
{
// print the mapped java class
PrintWriter holderOut = new PrintWriter(new java.io.FileWriter(file));
printHolderClass(className, holderOut);
holderOut.close();
}
fname = className + "Helper.java";
file = new File(dir, fname);
if (GlobalInputStream.isMoreRecentThan(file))
{
// print the mapped java class
PrintWriter helperOut = new PrintWriter(new java.io.FileWriter(file));
printHelperClass(className, helperOut);
helperOut.close();
}
written = true;
}
}
catch (java.io.IOException e)
{
throw new RuntimeException("File IO error" + e);
}
}
public void printInsertIntoAny(PrintWriter out,
String anyname,
String varname)
{
out.println("\t" + helperName() + ".insert(" + anyname + ", " + varname + " );");
}
public void printExtractResult(PrintWriter out,
String resultname,
String anyname,
String resulttype)
{
throw new RuntimeException("DII Stubs not yet complete for Sequence types");
}
}