/*
 *  ServerCallVisitor.java v0.10 20-DEC-1999
 *  Copyright (c) TKK/TLM/Calypso
 *  Author: Alexey Mednonogov
 */

package codec.visit;

import java.io.*;
import java.util.*;

import codec.*;
import codec.adapt.*;
import codec.convert.*;
import codec.debug.*;
import codec.dyntree.*;
import codec.export.*;
import codec.orb.*;
import codec.pco.*;
import codec.server.*;
import codec.client.*;
import codec.visit.*;
import codec.build.*;

/** Class implementing introspection of Server Call PDU received from
 *  Tester in order to prepare a request to Server. */
public class ServerCallVisitor extends InvocationAspVisitor {

    // --------------------- CLASS OUTPUT PARAMETERS --------------------

   	protected ServantRequest servantRequest;

   	/** Get invocation request prepared by Visitor. */
   	public ServantRequest getServantRequest()
        throws com.t3.ot.misc.OtException {

		if (servantRequest == null) finalizeVisitor();
		return servantRequest;
	}

    // ----------------------- CLASS CONSTRUCTOR ------------------------

   	public ServerCallVisitor(String pcoName_, com.t3.ot.pco.ASP asp_)
		throws com.t3.ot.misc.OtException {

		super(pcoName_, asp_);

		// Add this section to allow subclasses derived from this class
		// override initialization procedure introduced by it:

        Class thisClass = null;
        try { thisClass = Class.forName(
			"codec.visit.ServerCallVisitor"); }
        catch (ClassNotFoundException cnfe) { }

        if (!this.getClass().getName().equals(
			thisClass.getName())) return;

        // "This" class initialization procedure:
		servantRequest = null;

        // Get CORBA object for which request is being prepared:
		CodecObject codec = CorbaServer.getCodecObject();

        CorbaObject corbaObject =
            codec.getCorbaObjectPool().getObject(pcoName);

        if (corbaObject == null) throw new VisitorPcoUnreg();

		if (corbaObject.getPcoType() != CorbaObject.PCO_TYPE_SERVER)
			throw new VisitorNotServer();

        object = corbaObject.getObject();

        // Extract name scope of the operation
        // and check validity of PDU name:
        opNameScope = null;

        if (asp.getName().startsWith("pCALL_i")) {
            opNameScope = AspConverter.extractNameScope(asp.getName());
        }
        if (opNameScope == null) throw new VisitorInvalidFormat(
			"PDU identifier is constructed incorrectly.");

		String opName = opNameScope[opNameScope.length - 1];

		// Discover whether we are dealing with normal operation or
		// we are dealing with get/set method of an attribute:

		if ((opName.length() > 5) && 
			(opName.substring(0, 5).equals("_set_") ||
			 opName.substring(0, 5).equals("_get_"))) {

			opAttrDefClass = DEF_ATTRIBUTE;

			if (opName.substring(0, 5).equals("_set_"))
				 attrOptions = ATTR_OPTIONS_SET;
			else attrOptions = ATTR_OPTIONS_GET;
		}
		else {
			opAttrDefClass = DEF_OPERATION;
		}

		// Discover operation/attribute definition and check whether requested
		// operation/attribute is actually defined in Interface Repository:

		if (opAttrDefClass == DEF_OPERATION) {

			org.omg.CORBA.OperationDef opDef;
			opDef = Repository.getOperationDef(opNameScope);
			if (opDef == null) throw new VisitorOperationUndef();

			if (opDef.contexts().length != 0)
            { isContextPresent = true; }
			else { isContextPresent = false; }

			opAttrDef = opDef;
		}
		else {
			org.omg.CORBA.AttributeDef attrDef;
			attrDef = Repository.getAttributeDef(opNameScope);
			if (attrDef == null) throw new VisitorAttributeUndef();

            isContextPresent = false;
			opAttrDef = attrDef;
		}

		// Prepare NVList from operation/attribute description:
		if (opAttrDefClass == DEF_OPERATION) {

			nvList = orb.create_operation_list(
				(org.omg.CORBA.OperationDef) opAttrDef);
		}
		else {
			nvList = orb.create_list(1);
			if (attrOptions == ATTR_OPTIONS_SET) {

				org.omg.CORBA.Any any = orb.create_any();
				any.type(((org.omg.CORBA.AttributeDef) opAttrDef).type());

				nvList.add_value(opName.substring(5, 6), any,
					org.omg.CORBA.ARG_IN.value);
			}
		}

        // Create operation context:
		context = orb.get_default_context();
        context = context.create_child("child_context");

        // Assign initial state to state automaton represented by Visitor:
		adapter = new VisitorAdapter();
		adapter.create(nvList, null, VisitorAdapter.OPTIONS_SERVER_CALL);
		dynIterator = adapter.iterator();
	}

    // ----------------------- CLASS POSTPROCESSOR ----------------------

   	/** Make final actions on invocation request prepared by Visitor
     *  after Visitor is accepted. */
   	protected void finalizeVisitor() throws com.t3.ot.misc.OtException {

        super.finalizeVisitor();

        // Add this section to allow subclasses derived from this class
		// override finalization procedure introduced by it:

        Class thisClass = null;
        try { thisClass = Class.forName(
			"codec.visit.ServerCallVisitor"); }
        catch (ClassNotFoundException cnfe) { }

        if (!this.getClass().getName().equals(
			thisClass.getName())) return;

        // "This" class finalization procedure:
		org.omg.CORBA.Any any = orb.create_any();
		int i;

		if (opAttrDefClass == DEF_OPERATION) {
			any.type(((org.omg.CORBA.OperationDef) opAttrDef).result());
		}
		else {
			if (attrOptions == ATTR_OPTIONS_SET) {

				any.type(orb.get_primitive_tc(
					org.omg.CORBA.TCKind.tk_void));
			}
			else {
				any.type(((org.omg.CORBA.AttributeDef) opAttrDef).type());
			}
		}

        org.omg.CORBA.NamedValue result = orb.create_named_value(
            "RET_value", any, org.omg.CORBA.ARG_OUT.value);
        String opName = opNameScope[opNameScope.length - 1];

        adapter.updateContents();

        org.omg.CORBA.Request request = 
            object._create_request(context, opName, nvList, result);

		// Tell "request" object which context properties shall be
		// actually sent to Server during invocation:

		org.omg.CORBA.OperationDef opDef = null;

		if ((opAttrDefClass == DEF_OPERATION) && isContextPresent) {

			opDef = (org.omg.CORBA.OperationDef) opAttrDef;
			String[] propertyNames = opDef.contexts();

			for (i = 0; i < propertyNames.length; i++)
				request.contexts().add(propertyNames[i]);
		}

		// Tell "request" object which exceptions Server may raise:

		if (opAttrDefClass == DEF_OPERATION) {

		    opDef = (org.omg.CORBA.OperationDef) opAttrDef;
			org.omg.CORBA.ExceptionDef[] exDefs = opDef.exceptions();

			for (i = 0; i < exDefs.length; i++)
				request.exceptions().add(exDefs[i].type());
		}

        servantRequest = new ServantRequest(
			pcoName, asp.getName(), callID, request);
	}

    // ---------------------- CLASS VISITOR METHODS ---------------------

    public void visitBooleanValue(com.t3.ot.misc.BooleanValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

		boolean boolVal = value.getBoolean();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkLeaf(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());
		checkDiscriminator(dynNode, value.getName());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_boolean:
   			any.insert_boolean(boolVal);
   			break;

   		default:
   			throw new VisitorInvalidFormat(
   				"PDU contains BOOLEAN field \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
				Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}

	}

    public void visitCharStringValue(com.t3.ot.misc.StringValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		if (checkContextInCharStringValue(value)) return;
		checkDynIterator();

		String strVal = value.getCharString();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkLeaf(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());
		checkDiscriminator(dynNode, value.getName());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_string:

   			any.insert_string(strVal);
   			break;

		case org.omg.CORBA.TCKind._tk_char:
			if (strVal.length() != 1) {

				throw new VisitorInvalidFormat(
					"PDU contains CharacterString field \"" + 
					value.getName() + "\" that shall be exactly " +
					"of size 1 to represent IDL char, but its size " +
                    "is different.");
			}
   			any.insert_char(strVal.charAt(0));
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains CharacterString field \"" + value.getName()
                + "\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}
	}

    public void visitChoiceBegin(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkBegOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_union:
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains Beginning of CHOICE \"" +
				value.getName() + "\" that does not match " +
				"definition from Interface Repository (\"" +
				dynNode.name() + "\", " + Debug.tcKindToString(
					AnyGeneric.removeAliases(
						dynNode.value().type()).kind()) + ").");
   		}

        // At this point iterator does not match contents of PDU since we
		// did not know which branch of union would be used when we have
		// been constructing iterator. Now we have value of discriminator,
		// so it's hightime to update iterator:
		if (discriminator == null) {
			throw new VisitorInvalidFormat(
   				"PDU contains Beginning of CHOICE \"" + value.getName() + 
   			    "\" without matching discriminator.");
		}
		adapter.updateUnion(dynIterator, discriminator);
		dynIterator = adapter.iterator();
		discriminator = null;
	}

    public void visitChoiceEnd(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkEndOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_union:
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains End of CHOICE \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}
	}

    public void visitEnumeratedValue(com.t3.ot.misc.EnumeratedValue value)
		throws com.t3.ot.misc.OtException {

        checkTableAndCallid();
		checkDynIterator();

		long longVal = (long) value.getInt();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkLeaf(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());
		checkDiscriminator(dynNode, value.getName());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_enum:

			if ((longVal < (long) 0) || 
   				(longVal > ((((long) Integer.MAX_VALUE) << 1) | 1)))
            { throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"enum\") is out of bounds."); }

			org.omg.CORBA.DynEnum dynEnum = null;
			try {
				dynEnum = orb.create_dyn_enum(any.type());
			}
   			catch (org.omg.CORBA.ORBPackage.InconsistentTypeCode itc) {
	   			System.err.println("ServerCallVisitor::visitEnumeratedValue():"
                    + " Internal error -- CORBA exception (_tk_enum).");
				System.exit(0);
			}

			if (dynEnum == null) {
				System.err.println("ServerCallVisitor::visitEnumeratedValue():"
                    + " Internal error -- null pointer (_tk_enum).");
				System.exit(0);
			}

			dynEnum.value_as_ulong((int) longVal);
			AnyGeneric.dynAnyToAny(any, dynEnum);
			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains ENUMERATED field \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}
	}

    public void visitIntegerValue(com.t3.ot.misc.IntegerValue value)
		throws com.t3.ot.misc.OtException {

   		if (tableState != STATE_TABLE_ACTIVE)
			throw new VisitorInvalidFormat(
				"Incorrect definition of TTCN table.");
        if ((callidState != STATE_CALLID_PARSED) &&
			(value.getName().equals("CALL_ID") == false))
			throw new VisitorInvalidFormat(
                "CALL_ID shall be the first field of PDU.");

		String strVal = value.getIntegerAsString();
		long longVal = 0;
		try 
            { longVal = Long.parseLong(strVal); }
		catch (NumberFormatException nfe)
		    { throw new VisitorInvalidFormat(
				"Non-parseable INTEGER value was declared."); }

		if (value.getName().equals("CALL_ID") &&
			(callidState != STATE_CALLID_PARSED)) {

			callidState = STATE_CALLID_PARSED;
			callID = longVal;
			return;
		}

		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkLeaf(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());
		checkDiscriminator(dynNode, value.getName());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_longlong:
   			any.insert_longlong((long) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_long:
   			if ((longVal < (long) Integer.MIN_VALUE) || 
   				(longVal > (long) Integer.MAX_VALUE))
   			{ throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"long\") is out of bounds."); }
   			any.insert_long((int) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_short:
   			if ((longVal < (long) Short.MIN_VALUE) || 
   				(longVal > (long) Short.MAX_VALUE)) 
			{ throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"short\") is out of bounds."); }
   			any.insert_short((short) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_octet:

            /* Do NOT remove handling for IDL octet coming from Tester as
               INTEGER even though similar procedure is defined in
               visitOctetStringValue(). CORBA/TTCN Gateway specification
               allows using both OCTETSTRING and INTEGER. */

   			if ((longVal < (long) -128) ||
   				(longVal > (long)  255))
		    { throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"octet\") is out of bounds."); }
   			any.insert_octet((byte) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_ulonglong:
   			any.insert_ulonglong((long) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_ulong:
   			if ((longVal < (long) 0) || 
   				(longVal > ((((long) Integer.MAX_VALUE) << 1) | 1)))
            { throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"unsigned long\") is out of bounds."); }
   			any.insert_ulong((int) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_ushort:
   			if ((longVal < (long) 0) || 
   				(longVal > ((((long) Short.MAX_VALUE) << 1) | 1)))
            { throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"unsigned short\") is out of bounds."); }
   			any.insert_ushort((short) longVal);
   			break;

   		case org.omg.CORBA.TCKind._tk_enum:

            /* Do NOT remove handling for IDL enum coming from Tester as
               INTEGER even though similar procedure is defined in
               visitEnumeratedValue(). CORBA/TTCN Gateway specification
               allows using both ENUMERATED and INTEGER. */

			if ((longVal < (long) 0) || 
   				(longVal > ((((long) Integer.MAX_VALUE) << 1) | 1)))
            { throw new VisitorInvalidFormat(
   				"Value of PDU field \"" + value.getName() +
                  "\" (IDL type \"enum\") is out of bounds."); }

			org.omg.CORBA.DynEnum dynEnum = null;
			try {
				dynEnum = orb.create_dyn_enum(any.type());
			}
   			catch (org.omg.CORBA.ORBPackage.InconsistentTypeCode itc) {
	   			System.err.println("ServerCallVisitor::visitIntegerValue():"
                    + " Internal error -- CORBA exception (_tk_enum).");
				System.exit(0);
			}

			if (dynEnum == null) {
				System.err.println("ServerCallVisitor::visitIntegerValue():"
                    + " Internal error -- null pointer (_tk_enum).");
				System.exit(0);
			}

			dynEnum.value_as_ulong((int) longVal);
			AnyGeneric.dynAnyToAny(any, dynEnum);
			break;
            
   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains INTEGER field \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}
	}

    public void visitOctetStringValue(com.t3.ot.misc.StringValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

		String strVal = value.getOctetString();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkLeaf(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());
		checkDiscriminator(dynNode, value.getName());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

		case org.omg.CORBA.TCKind._tk_octet:
			
			byte[] octetArray = null;
	   		octetArray = Converter.octetStringToBytes(strVal);

			if (octetArray.length != 1) {

				throw new VisitorInvalidFormat(
					"PDU contains OCTETSTRING field \"" + 
					value.getName() + "\" that shall represent " +
					"exactly 1 octet, but it does not.");
			}
   			any.insert_octet(octetArray[0]);
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains OCTETSTRING field \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
		}
	}

    public void visitSequenceBegin(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkBegOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_struct:
   		case org.omg.CORBA.TCKind._tk_except:
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains Beginning of SEQUENCE \"" +
				value.getName() + "\" that does not match " +
				"definition from Interface Repository (\"" +
				dynNode.name() + "\", " + Debug.tcKindToString(
					AnyGeneric.removeAliases(
						dynNode.value().type()).kind()) + ").");
   		}
	}

    public void visitSequenceEnd(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkEndOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_struct:
   		case org.omg.CORBA.TCKind._tk_except:
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains End of SEQUENCE \"" + value.getName() +
				"\" that does not match definition from " +
				"Interface Repository (\"" + dynNode.name() + "\", " +
			    Debug.tcKindToString(AnyGeneric.removeAliases(
					dynNode.value().type()).kind()) +
				").");
   		}
	}

    public void visitSequenceOfBegin(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		if (checkContextInSequenceOfBegin(value)) return;
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkBegOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);
   		org.omg.CORBA.Any any = dynNode.value();

   		switch (kind) {

   		case org.omg.CORBA.TCKind._tk_sequence:

			// At this point iterator does not match contents of PDU since we
			// did not know how many items sequence would contain when we have
			// been constructing iterator. Now we have this information, so
			// it's hightime to update iterator:

			adapter.updateSequence(dynIterator, value.getLength());
			dynIterator = adapter.iterator();
			break;

		case org.omg.CORBA.TCKind._tk_array:
   			break;

   		default:
			throw new VisitorInvalidFormat(
   				"PDU contains Beginning of SEQUENCE OF \"" +
				value.getName() + "\" that does not match " +
				"definition from Interface Repository (\"" +
				dynNode.name() + "\", " + Debug.tcKindToString(
					AnyGeneric.removeAliases(
						dynNode.value().type()).kind()) + ").");
   		}
	}

    public void visitSequenceOfEnd(com.t3.ot.misc.StructValue value)
		throws com.t3.ot.misc.OtException {

		checkTableAndCallid();
		if (checkContextInSequenceOfEnd(value)) return;
		checkDynIterator();

   		// Obtain next parameter and its type:
		DynNode dynNode = dynIterator.next();
		checkEndOfNode(dynNode, value.getName());
   		checkAspFieldName(value.getName(), dynNode.name());

   		int kind = getDynNodeKind(dynNode);

   		switch (kind) {

   		    case org.omg.CORBA.TCKind._tk_sequence:
		    case org.omg.CORBA.TCKind._tk_array:
   			    break;

   		    default:
			    throw new VisitorInvalidFormat(
   				    "PDU contains End of SEQUENCE OF \"" +
				    value.getName() + "\" that does not match " +
				    "definition from Interface Repository (\"" +
				    dynNode.name() + "\", " + Debug.tcKindToString(
					    AnyGeneric.removeAliases(
					    dynNode.value().type()).kind()) + ").");
   		}
	}
}
