When -tables option is used, open type fields are generated as Asn1Type fields. The general procedure to populate the value for these fields is as follows:
Check the possible Type in ObjectSet from index element value.
Populate the value for this type and assign it to the open type member variable.
Follow the common encode procedure.
A complete example showing how to assign open type values when table constraint code is generated is as follows:
ATTRIBUTE ::= CLASS { &Type, &id OBJECT IDENTIFIER UNIQUE } WITH SYNTAX { WITH SYNTAX &Type ID &id } name ATTRIBUTE ::= { WITH SYNTAX VisibleString ID { 0 1 1 } } commonName ATTRIBUTE ::= { WITH SYNTAX INTEGER ID { 0 1 2 } } SupportedAttributes ATTRIBUTE ::= { name | commonName } Invoke ::= SEQUENCE { opcode ATTRIBUTE.&id ({SupportedAttributes}), argument ATTRIBUTE.&Type ({SupportedAttributes}{@opcode}) }
In the above example, the Invoke type contains a relative table constraint. Its element opcode refers to the ATTRIBUTE class's id field and the argument element refers to ATTRIBUTE class's Type field. The opcode element is the index element into the {SupportedAttributes} information object set. The argument element is an open type but its type must match that specified at the location in the {SupportedAttributes} information object set indexed by opcode.
In this example, opcode can have only two possible values { 0 1 1 } or { 0 1 2 }. If the opcode value is { 0 1 1} then argument must be a value of type VisibleString. If the opcode value is { 0 1 2 } then argument will have an INTEGER value. Any other value of the opcode element will be a violation of the Table Constraint.
If the SupportedAttributes object set was extensible (in this example, it is not), then the argument element can be a value of any type. In this case, if the user is using an index element value outside the object set, then the user will have to encode the argument element as an Asn1OpenType.
The following sample code populates the open type value:
// Step 1: populate the "Invoke" type with data Invoke pdu = new Invoke(); pdu.opcode = new Asn1ObjectIdentifier(new int[]{0, 1, 1}); pdu.argument = new Asn1VisibleString("objsys"); // note: opcode value is {0 1 1 }, so argument must be // Asn1VisibleString type // note: the rest of the encode method will be same as general // PER/DER/BER encoding rules // Step 2: Create a message buffer object. Asn1PerEncodeBuffer encodeBuffer = new Asn1PerEncodeBuffer(); // Step 3: Invoke the encode method. Note that it must be done // from within a try/catch block.. try { pdu.encode (encodeBuffer); if (trace) { System.out.println ("Encoding was successful"); System.out.println ("Hex dump of encoded record:"); encodeBuffer.hexDump (); System.out.println ("Binary dump:"); encodeBuffer.binDump ("Invoke"); } // Step 3: Access the encoded message component. In this // case, we use methods in the class to write the component // to a file and output a formatted dump to the message.dmp // file.. // Write the encoded record to a file encodeBuffer.write (new FileOutputStream (filename)); // Generate a dump file for comparisons encodeBuffer.hexDump (new PrintStream (new FileOutputStream ("message.dmp"))); // We can also directly access the buffer as follows: byte[] buffer = encodeBuffer.getBuffer(); int msglen = encodeBuffer.getMsgByteCnt(); } catch (Exception e) { System.out.println (e.getMessage()); e.printStackTrace(); return; }
The important thing to note is that not much changes from the normal procedure. The only significant difference is that now the argument field can be directly populated with an instance of its target type. Without table constraint checking logic, this value would have to have been first encoded and then placed in an Asn1OpenType container object.