// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
= Binary Type Metadata

== Operation Codes

Upon a successful handshake with an Ignite server node a client can start performing binary-type related operations by sending a request (see request/response structure below) with a specific operation code:



[cols="2,1",opts="header"]
|===
|Operation  | OP_CODE
|OP_GET_BINARY_TYPE_NAME| 3000
|OP_REGISTER_BINARY_TYPE_NAME|    3001
|OP_GET_BINARY_TYPE | 3002
|OP_PUT_BINARY_TYPE|  3003
|OP_RESOURCE_CLOSE|   0
|===


Note that the above mentioned op_codes are part of the request header, as explained link:binary-client-protocol/binary-client-protocol#standard-message-header[here].

[NOTE]
====
[discrete]
=== Customs Methods Used in Sample Code Snippets Implementation

Some of the code snippets below use `readDataObject(...)` introduced in link:binary-client-protocol/binary-client-protocol#data-objects[this section] and little-endian versions of methods for reading and writing multiple-byte values that are covered in link:binary-client-protocol/binary-client-protocol#data-objects[this example].
====


== OP_GET_BINARY_TYPE_NAME

Gets the platform-specific full binary type name by id. For example, .NET and Java can map to the same type Foo, but classes will be Apache.Ignite.Foo in .NET and org.apache.ignite.Foo in Java.

Names are registered with OP_REGISTER_BINARY_TYPE_NAME.


[cols="1,2",opts="header"]
|===
|Request Type   | Description
|Header |  Request header.
|byte |    Platform id:
JAVA = 0
DOTNET = 1
|int| Type id; Java-style hash code of the type name.
|===


[cols="1,2",opts="header"]
|===
|Response Type  |Description
|Header |  Response header.
|String |  Binary type name.
|===


[tabs]
--
tab:Request[]

[source, java]
----
String type = "ignite.myexamples.model.Person";
int typeLen = type.getBytes("UTF-8").length;

DataOutputStream out = new DataOutputStream(socket.getOutputStream());

// Request header
writeRequestHeader(5, OP_GET_BINARY_TYPE_NAME, 1, out);

// Platform id
writeByteLittleEndian(0, out);

// Type id
writeIntLittleEndian(type.hashCode(), out);
----


tab:Response[]

[source, java]
----
// Read result
DataInputStream in = new DataInputStream(socket.getInputStream());

// Response header
readResponseHeader(in);

// Resulting String
int typeCode = readByteLittleEndian(in); // type code
int strLen = readIntLittleEndian(in); // length

byte[] buf = new byte[strLen];

readFully(in, buf, 0, strLen);

String s = new String(buf);

System.out.println(s);
----


--

== OP_GET_BINARY_TYPE

Gets the binary type information by id.


[cols="1,2",opts="header"]
|===
|Request Type   | Description
|Header |  Request header.
|int | Type id; Java-style hash code of the type name.
|===



[cols="1,2",opts="header"]
|===
| Response Type | Description
|Header|  Response header.
|bool|    False: binary type does not exist, response end.
True: binary type exists, response as follows.
|int| Type id; Java-style hash code of the type name.
|String|  Type name.
|String|  Affinity key field name.
|int| BinaryField count.
|BinaryField * count| Structure of BinaryField:

`String`  Field name

`int` Type id; Java-style hash code of the type name.

`int` Field id; Java-style hash code of the field name.

|bool|    Is Enum or not.

If set to true, then you have to pass the following 2 parameters. Otherwise, skip them.
|int| _Pass only if 'is enum' parameter is 'true'_.

Enum field count.
|String + int|    _Pass only if 'is enum' parameter is 'true'_.

Enum values. An enum value is a pair of a literal value (String) and numerical value (int).

Repeat for as many times as the Enum field count that is obtained in the previous parameter.

|int| Schema count.
|BinarySchema|    Structure of BinarySchema:

`int` Unique schema id.

`int` Number of fields in the schema.

`int` Field Id; Java-style hash code of the field name. Repeat for as many times as the total number of fields in the schema.

Repeat for as many times as the BinarySchema count that is obtained in the previous parameter.
|===


[tabs]
--
tab:Request[]

[source, java]
----
String type = "ignite.myexamples.model.Person";

DataOutputStream out = new DataOutputStream(socket.getOutputStream());

// Request header
writeRequestHeader(4, OP_BINARY_TYPE_GET, 1, out);

// Type id
writeIntLittleEndian(type.hashCode(), out);
----

tab:Response[]

[source, java]
----
// Read result
DataInputStream in = new DataInputStream(socket.getInputStream());

readResponseHeader(in);

boolean typeExist = readBooleanLittleEndian(in);

int typeId = readIntLittleEndian(in);

String typeName = readString(in);

String affinityFieldName = readString(in);

int fieldCount = readIntLittleEndian(in);

for (int i = 0; i < fieldCount; i++)
    readBinaryTypeField(in);

boolean isEnum = readBooleanLittleEndian(in);

int schemaCount = readIntLittleEndian(in);

// Read binary schemas
for (int i = 0; i < schemaCount; i++) {
  int schemaId = readIntLittleEndian(in); // Schema Id

  int fieldCount = readIntLittleEndian(in); // field count

  for (int j = 0; j < fieldCount; j++) {
    System.out.println(readIntLittleEndian(in)); // field id
  }
}

private static void readBinaryTypeField (DataInputStream in) throws IOException{
  String fieldName = readString(in);
  int fieldTypeId = readIntLittleEndian(in);
  int fieldId = readIntLittleEndian(in);
  System.out.println(fieldName);
}
----
--


== OP_REGISTER_BINARY_TYPE_NAME

Registers the platform-specific full binary type name by id. For example, .NET and Java can map to the same type Foo, but classes will be Apache.Ignite.Foo in .NET and org.apache.ignite.Foo in Java.


[cols="1,2",opts="header"]
|===
|Request Type  | Description
|Header |  Request header.
|byte|    Platform id:
JAVA = 0
DOTNET = 1
|int| Type id; Java-style hash code of the type name.
|String|  Type name.
|===



[cols="1,2",opts="header"]
|===
|Response Type  |Description
|Header | Response header.
|===

[tabs]
--
tab:Request[]

[source, java]
----
String type = "ignite.myexamples.model.Person";
int typeLen = type.getBytes("UTF-8").length;

DataOutputStream out = new DataOutputStream(socket.getOutputStream());

// Request header
writeRequestHeader(20 + typeLen, OP_PUT_BINARY_TYPE_NAME, 1, out);

//Platform id
writeByteLittleEndian(0, out);

//Type id
writeIntLittleEndian(type.hashCode(), out);

// Type name
writeString(type, out);
----

tab:Response[]

[source, java]
----
// Read result
DataInputStream in = new DataInputStream(socket.getInputStream());

readResponseHeader(in);
----

--

== OP_PUT_BINARY_TYPE

Registers binary type information in cluster.


[cols="1,2",opts="header"]
|===
|Request Type |  Description
|Header|  Response header.
|int| Type id; Java-style hash code of the type name.
|String|  Type name.
|String|  Affinity key field name.
|int| BinaryField count.
|BinaryField| Structure of BinaryField:

`String`  Field name

`int` Type id; Java-style hash code of the type name.

`int` Field id; Java-style hash code of the field name.

Repeat for as many times as the BinaryField count that is passed in the previous parameter.
|bool|    Is Enum or not.

If set to true, then you have to pass the following 2 parameters. Otherwise, skip them.
|int| Pass only if 'is enum' parameter is 'true'.

Enum field count.
|String + int|    Pass only if 'is enum' parameter is 'true'.

Enum values. An enum value is a pair of a literal value (String) and numerical value (int).

Repeat for as many times as the Enum field count that is passed in the previous parameter.
|int| BinarySchema count.
|BinarySchema|    Structure of BinarySchema:

`int` Unique schema id.

`int` Number of fields in the schema.

`int` Field id; Java-style hash code of the field name. Repeat for as many times as the total number of fields in the schema.

Repeat for as many times as the BinarySchema count that is passed in the previous parameter.
|===


[cols="1,2",opts="header"]
|===
| Response Type | Description
|Header |  Response header.
|===


[tabs]
--
tab:Request[]

[source, java]
----
String type = "ignite.myexamples.model.Person";

DataOutputStream out = new DataOutputStream(socket.getOutputStream());

// Request header
writeRequestHeader(120, OP_BINARY_TYPE_PUT, 1, out);

// Type id
writeIntLittleEndian(type.hashCode(), out);

// Type name
writeString(type, out);

// Affinity key field name
writeByteLittleEndian(101, out);

// Field count
writeIntLittleEndian(3, out);

// Field 1
String field1 = "id";
writeBinaryTypeField(field1, "long", out);

// Field 2
String field2 = "name";
writeBinaryTypeField(field2, "String", out);

// Field 3
String field3 = "salary";
writeBinaryTypeField(field3, "int", out);

// isEnum
out.writeBoolean(false);

// Schema count
writeIntLittleEndian(1, out);

// Schema
writeIntLittleEndian(657, out);  // Schema id; can be any custom value
writeIntLittleEndian(3, out);  // field count
writeIntLittleEndian(field1.hashCode(), out);
writeIntLittleEndian(field2.hashCode(), out);
writeIntLittleEndian(field3.hashCode(), out);

private static void writeBinaryTypeField (String field, String fieldType, DataOutputStream out) throws IOException{
  writeString(field, out);
  writeIntLittleEndian(fieldType.hashCode(), out);
  writeIntLittleEndian(field.hashCode(), out);
}
----

tab:Response[]

[source, java]
----
// Read result
DataInputStream in = new DataInputStream(socket.getInputStream());

readResponseHeader(in);
----

--

