@EndUserText.label : 'Kotlin Tester'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table ztest_kotlin {
key mandt : mandt not null;
key guid : /aif/exp_guid not null;
date_updated : sydatum;
time_updated : syuzeit;
last_updated_by : syuname;
order_number : vbeln;
customer_number : kunag;
customer_message : zz_note;
}
method CUSTOMERMEMOSET_GET_ENTITYSET.
SELECT * FROM ztest_kotlin INTO TABLE et_entityset.
SORT et_entityset BY date_updated DESCENDING time_updated DESCENDING.
endmethod.
method CUSTOMERMEMOSET_GET_ENTITY.
DATA: ls_entity LIKE er_entity.
io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_entity ).
SELECT SINGLE * FROM ztest_kotlin INTO er_entity
WHERE guid = ls_entity-guid.
endmethod.
/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet(guid'0ed254e2-d1e6-1eda-809f-8d77d746d4dd')?$format=json
METHOD customermemoset_create_entity.
DATA: lw_record TYPE zcl_zkotlin_app_mpc=>ts_customermemo.
io_data_provider->read_entry_data( IMPORTING es_data = lw_record ).
IF lw_record-order_number IS INITIAL OR
lw_record-customer_number IS INITIAL OR
lw_record-customer_message IS INITIAL.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception.
ENDIF.
"Create a record in the database...
CLEAR: lw_record-date_updated, lw_record-time_updated, lw_record-last_updated_by,
lw_record-guid.
lw_record-date_updated = sy-datum.
lw_record-time_updated = sy-uzeit.
lw_record-last_updated_by = sy-uname.
"Generate a unique key (guid)...
TRY.
lw_record-guid = cl_system_uuid=>if_system_uuid_static~create_uuid_x16( ).
CATCH cx_uuid_error INTO DATA(lo_guid_error).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception.
ENDTRY.
INSERT ztest_kotlin FROM lw_record.
COMMIT WORK AND WAIT.
IF sy-subrc = 0.
"New record was created successfully...
er_entity = lw_record.
ELSE.
"Entity not found
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>resource_not_found
entity_type = iv_entity_name.
ENDIF.
ENDMETHOD.
"Generate a unique key (guid)...
TRY.
lw_record-guid = cl_system_uuid=>if_system_uuid_static~create_uuid_x16( ).
CATCH cx_uuid_error INTO DATA(lo_guid_error).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception.
ENDTRY.
/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet(guid'0ed254e2-d1e6-1eda-809f-8d77d746d4dd')?$format=json
/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet(guid'0ed254e2-d1e6-1eea-8dfa-d2e289485cae')?$format=json
http://<your server name>/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet
{
"d": {
"Guid": "00000000-0000-0000-0000-000000000000",
"OrderNumber": "8888",
"CustomerNumber": "9999",
"CustomerMessage": "This is a new Memo from the Advanced REST Client!"
}
}
method CUSTOMERMEMOSET_UPDATE_ENTITY.
DATA: lw_record TYPE zcl_zkotlin_app_mpc=>ts_customermemo.
io_data_provider->read_entry_data( IMPORTING es_data = lw_record ).
"The key is "guid"...
READ TABLE it_key_tab INTO DATA(lw_key) INDEX 1.
"Make sure the value matches the one in the OData payload...
IF lw_key-value = lw_record-guid.
"Update the record in the database...
CLEAR: lw_record-date_updated, lw_record-time_updated, lw_record-last_updated_by.
lw_record-date_updated = sy-datum.
lw_record-time_updated = sy-uzeit.
lw_record-last_updated_by = sy-uname.
UPDATE ztest_kotlin FROM lw_record.
COMMIT WORK AND WAIT.
IF sy-subrc = 0.
"Entity was found and updated...
er_entity = lw_record.
ELSE.
"Entity not found
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>resource_not_found
entity_type = |{ iv_entity_name } ('{ lw_key-value }')|.
ENDIF.
ENDIF.
endmethod.
/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet(Guid=guid'0ed254e2-d1e6-1eda-8fb0-2a4781e3b5c5')
{
"d" : {
"Guid" : "0ed254e2-d1e6-1eda-8fb0-2a4781e3b5c5",
"DateUpdated" : "\/Date(1578528000000)\/",
"TimeUpdated" : "PT13H10M38S",
"LastUpdatedBy" : "JCAPPS",
"OrderNumber" : "8888",
"CustomerNumber" : "9999",
"CustomerMessage" : "This is my updated Memo!"
}
}
METHOD customermemoset_delete_entity.
DATA(lt_keys) = io_tech_request_context->get_keys( ).
READ TABLE lt_keys WITH KEY name = 'GUID' INTO DATA(ls_key).
DATA(lv_guid) = ls_key-value.
"Ensure the GUID is valid...
SELECT SINGLE mandt INTO @DATA(l_mandt) FROM ztest_kotlin
WHERE guid = @lv_guid.
IF sy-subrc <> 0.
"Record not found...
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>resource_not_found
entity_type = |{ iv_entity_name } (Guid='{ lv_guid }')|.
ENDIF.
"Delete the record from the database...
DELETE FROM ztest_kotlin WHERE guid = lv_guid.
COMMIT WORK AND WAIT.
IF sy-subrc <> 0.
"Delete Failed...
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = /iwbep/cx_mgw_busi_exception=>resource_not_found
entity_type = |{ iv_entity_name } (Guid='{ lv_guid }')|.
ENDIF.
ENDMETHOD.
/sap/opu/odata/SAP/ZKOTLIN_APP_SRV/CustomerMemoSet(Guid=guid'0ed254e2-d1e6-1eda-8fb0-2a4781e3b5c5')
compile "com.github.kittinunf.fuel:fuel:2.2.1"
compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+"
jcenter()
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.3.61'
}
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "com.github.kittinunf.fuel:fuel:2.2.1"
compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method main: Entry point for the program...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
fun main() {
println("Hello World!")
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method displayMainMenu: Display the user's options and prompt for input...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun displayMainMenu(): Int {
println()
println("Task Options: ")
println("(1) - Display All Data")
println("(2) - Display a Record")
println("(3) - Create a Record")
println("(4) - Update a Record")
println("(5) - Delete a Record")
println("(6) - Exit the Program")
print("Enter an Option Number: ")
var num = -1
try {
num = readLine()!!.toInt()
} catch (e: NumberFormatException) {
}
return num
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method main: Entry point for the program...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
fun main() {
//Process User Selection...
var answer = 0
while (answer != 6) {
answer = displayMainMenu()
when (answer) {
1 -> println("Proceeding to Display All Data...")
2 -> println("Proceeding to Display a Record...")
3 -> println("Proceeding to Create a Record...")
4 -> println("Proceeding to Update a Record...")
5 -> println("Proceeding to Delete a Record...")
6 -> {
println("\nThank you for using this amazing program!!...Goodbye...")
exitProcess(0)
}
else -> {
println()
println("Invalid Option Number. Please Enter a valid option number 1 thru 6.")
}
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Final Variables used throughout the program (val = Final, var = Variable)...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const val AUTH_STRING = "amNhcHBblahblahblahblahc="
const val MAIN_URL = "http://<your server>/sap/opu/odata/SAP/ZTEST_KOTLIN_SRV/ZTEST_KOTLINSet"
const val JSON_FORMAT = "?\$format=json"
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method main: Entry point for the program...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
fun main() {
val mapper = jacksonObjectMapper()
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// A data class which represents a single Customer Memo Record from the ZTEST_KOTLIN SAP table.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class CustomerMemoRecord(
var Guid: String = "",
var DateUpdated: String = "",
var TimeUpdated: String = "",
var LastUpdatedBy: String = "",
var OrderNumber: String = "",
var CustomerNumber: String = "",
var CustomerMessage: String = ""
)
val customerRecords: List<CustomerMemoRecord> = emptyList()
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Multiple Record GET - RootJsonNodeSet plus CustomerDataSet with all Customer Records...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class RootJsonNodeSet(
@JsonProperty("d")
val allRecords: CustomerDataSet
)
data class CustomerDataSet(
@JsonProperty("results")
val customerRecords: List<CustomerMemoRecord> = emptyList()
)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Single Record GET for one Customer Memo Record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
data class RootJsonNodeSingle(
@JsonProperty("d")
val singleCustomerRecord: CustomerMemoRecord
)
//Ignore any properties that don't exist in our CustomerMemoRecord Class...
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Data Class for a Fetch record, for CUD Operations...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class FetchRecord(
val CsrfToken: String,
val Cookie: String,
var singleCustomerRecord: CustomerMemoRecord
)
import com.fasterxml.jackson.annotation.JsonProperty
import kotlin.system.exitProcess
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method jsonDateFormatter: Parse a JSON Date (Epoch Date) into a Java/Kotlin Date
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun jsonDateFormatter(jsonDate: String): String {
val epochDate = jsonDate.replace("[^0-9]".toRegex(), "")
val updateDate = Instant.ofEpochMilli(java.lang.Long.parseLong(epochDate))
.atZone(ZoneId.of("CET"))
.toLocalDate()
return updateDate.toString()
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method jsonTimeFormatter: Parse a JSON Time (XSD:Duration Date Type) into Java/Kotlin Time
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun jsonTimeFormatter(jsonTime: String): String {
val fTime = LocalTime.ofNanoOfDay(Duration.parse(jsonTime).toNanos())
val df = DateTimeFormatter.ISO_LOCAL_TIME
return fTime.format(df)
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method displayDataSet: Display all records in the ZTEST_KOTLIN SAP table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun displayDataSet() {
println()
println("...One moment please, retrieving all records...")
FuelManager.instance.baseHeaders = mapOf("Authorization" to "Basic $AUTH_STRING")
val mapper = jacksonObjectMapper()
val url = MAIN_URL + JSON_FORMAT
//This allows you to parse out only the attributes you'd like, and ignore all others...
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val (_, _, result) = url.httpGet().responseString()
when (result) {
is Result.Failure -> {
val ex = result.getException()
print(ex)
}
is Result.Success -> {
val myJsonData: RootJsonNodeSet = mapper.readValue(result.get())
val memoRecords: List<CustomerMemoRecord> = myJsonData.allRecords.customerRecords
println("\nTable ZTEST_KOTLIN (${memoRecords.count()} Records):")
for (x in 0..80) print("=-") // Print 80 times for line separator...
println()
println("Guid (key) " +
"| Date " +
"| Time " +
"| Updated By " +
"| Order # " +
"| Customer # " +
"| Memo")
for (x in 0..80) print("=-") // Print 80 times...
println()
memoRecords.forEach {
println(
"${it.Guid} " +
"| ${jsonDateFormatter(it.DateUpdated)} " +
"| ${jsonTimeFormatter(it.TimeUpdated)} " +
"| ${it.LastUpdatedBy.padStart(12)} " + //pad to 12 characters, to line up with column header
"| ${it.OrderNumber.padStart(10)} " + //pad to 10 characters
"| ${it.CustomerNumber.padStart(10)} " + //pad to 10 characters
"| ${it.CustomerMessage}"
)
}
for (x in 0..80) print("=-") // Print 80 times...
println()
}
}
}
when (answer) {
1 -> displayDataSet() //<<<add this
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method promptTheUser: Prompt the end user for something...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun promptTheUser(message: String): String {
print(message)
return readLine()!!
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method fetchSingleRecord: Fetch Data for a Single Record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun fetchSingleRecord(lclUrl: String): FetchRecord {
val mapper = jacksonObjectMapper()
FuelManager.instance.baseHeaders = mapOf(
"Authorization" to "Basic $AUTH_STRING",
"X-CSRF-Token" to "Fetch"
)
//Ignore any properties that don't exist in our CustomerMemoRecord Class...
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val (_, response, result) = lclUrl.httpGet().responseString()
val csrfToken: String? = response.headers["x-csrf-token"].elementAt(0)
val cookie: String? = response.headers["set-cookie"].elementAt(0) + response.headers["set-cookie"].elementAt(1)
var memoRecord = CustomerMemoRecord()
when (result) {
is Result.Failure -> {
val ex = result.getException()
print(ex)
}
is Result.Success -> {
val myJsonData: RootJsonNodeSingle = mapper.readValue(result.get())
memoRecord = myJsonData.singleCustomerRecord
}
}
return FetchRecord(
CsrfToken = csrfToken.toString(),
Cookie = cookie.toString(),
singleCustomerRecord = memoRecord
)
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method showFormattedRecord: Display of a single record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun showFormattedRecord(record: CustomerMemoRecord, lclTitle: String) {
println()
for (x in 0..50) print("=-") // Print 50 times for line separator...
println()
println("$lclTitle Record for Order Number ${record.OrderNumber}:")
for (x in 0..50) print("=-") // Print 50 times...
println()
println(" Guid (key): ${record.Guid}")
println(" Date Last Updated: ${jsonDateFormatter(record.DateUpdated)}")
println(" Time Last Updated: ${jsonTimeFormatter(record.TimeUpdated)}")
println("Last Updated By User: ${record.LastUpdatedBy}")
println(" Order Number: ${record.OrderNumber}")
println(" Customer Number: ${record.CustomerNumber}")
println(" Customer Memo: ${record.CustomerMessage}")
for (x in 0..50) print("=-") // Print 50 times...
println()
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method displaySingleRecord: Display a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun displayRecord(lclGuid: String, lclTitle: String) {
val singleRecordString = "(Guid=guid'${lclGuid}')"
val lclUrl = MAIN_URL + singleRecordString + JSON_FORMAT
val fetchRecord = fetchSingleRecord(lclUrl)
showFormattedRecord( fetchRecord.singleCustomerRecord, lclTitle )
}
when (answer) {
1 -> displayDataSet()
2 -> displayRecord(promptTheUser("Enter a GUID to Display: "), "Current")
So we will prompt the user 3 times by calling our generic “promptTheUser” method.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method initializeFuel: Set the FuelManager for UPDATE or POST...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun initializeFuel(CsrfToken: String, Cookie: String) {
FuelManager.instance.baseHeaders = mapOf(
"Authorization" to "Basic $AUTH_STRING",
"X-CSRF-Token" to CsrfToken,
"cookie" to Cookie,
"Content-Type" to "application/json",
"Accept" to "application/json"
)
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method createRecord: Create a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun createRecord() {
val lclOrder = promptTheUser("Enter Order Number: ")
val lclCustomer = promptTheUser("Enter Customer Number: ")
val lclMemo = promptTheUser("Enter Customer Memo: ")
//First, fetch the CSRF Token and Cookie, prior to performing the POST...
var url = MAIN_URL + JSON_FORMAT
val fetchRecord = fetchSingleRecord(url)
fetchRecord.singleCustomerRecord.OrderNumber = lclOrder
fetchRecord.singleCustomerRecord.CustomerNumber = lclCustomer
fetchRecord.singleCustomerRecord.CustomerMessage = lclMemo
//Even though we are doing a POST (Create), we still need to fill in all of the
//attributes, so enter dummy data for these ignored fields...
fetchRecord.singleCustomerRecord.Guid = "00000000-0000-0000-0000-000000000000"
fetchRecord.singleCustomerRecord.DateUpdated = """/Date(1578441600000)/"""
fetchRecord.singleCustomerRecord.LastUpdatedBy = ""
fetchRecord.singleCustomerRecord.TimeUpdated = "PT13H12M09S"
val mapper = jacksonObjectMapper()
// The default mapper, adjusts the field names to lower case camel case, but our
// Gateway service has upper case (i.e. dateUpdated vs. DateUpdated),
// so we set the UPPER_CAMEL_CASE property here...
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// Serialize the fetchRecord Object back into a JSON String and use for our POST
// to create the Customer Memo...
val jsonString = mapper.writeValueAsString(fetchRecord.singleCustomerRecord)
//Remove the "jsonFormat" URI Option, prior to doing the POST...
url = MAIN_URL
val newRecord: CustomerMemoRecord
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val postString = """{ "d" : $jsonString }"""
//This is a synchronous "Blocking Mode" call (i.e. will wait for a response)...
val (_, _, result) = url.httpPost().body(postString).responseString()
when (result) {
is Result.Failure -> {
println()
println("Post Failed...")
println(result.getException().toString() + result.error.response.toString())
}
is Result.Success -> {
val myJsonData: RootJsonNodeSingle = mapper.readValue(result.get())
newRecord = myJsonData.singleCustomerRecord
println()
println("...Customer Memo successfully created...")
displayRecord(newRecord.Guid, "New")
}
}
}
when (answer) {
1 -> displayDataSet()
2 -> displayRecord(promptTheUser("Enter a GUID to Display: "), "Current")
3 -> createRecord()
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method updateRecord: Update a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun updateRecord() {
val lclGuid = promptTheUser("Enter a GUID to Update: ")
val newMemo = promptTheUser("Enter the New Memo: ")
var url = "$MAIN_URL(Guid=guid'$lclGuid')$JSON_FORMAT"
val fetchRecord = fetchSingleRecord(url)
val originalMemo = fetchRecord.singleCustomerRecord.CustomerMessage
fetchRecord.singleCustomerRecord.CustomerMessage = newMemo
val mapper = jacksonObjectMapper()
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
val jsonString = mapper.writeValueAsString(fetchRecord.singleCustomerRecord)
url = "$MAIN_URL(Guid=guid'$lclGuid')"
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val putString = """{ "d" : $jsonString }"""
val (_, _, result) = url.httpPut().body(putString).responseString()
when (result) {
is Result.Failure -> {
println(result.getException().toString())
}
is Result.Success -> {
println("...Customer Memo successfully updated...")
println("Old Memo: $originalMemo")
println("New Memo: $newMemo")
displayRecord(lclGuid, "Updated")
}
}
}
when (answer) {
1 -> displayDataSet()
2 -> displayRecord(promptTheUser("Enter a GUID to Display: "), "Current")
3 -> createRecord()
4 -> updateRecord()
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method deleteRecord: Delete a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun deleteRecord() {
val lclGuid = promptTheUser("Enter a GUID to Delete: ")
var url = "$MAIN_URL(Guid=guid'$lclGuid')$JSON_FORMAT"
val fetchRecord = fetchSingleRecord(url)
val mapper = jacksonObjectMapper()
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
url = "$MAIN_URL(Guid=guid'$lclGuid')"
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val (_, _, result) = url.httpDelete().responseString()
when (result) {
is Result.Failure -> {
println(result.getException().toString())
}
is Result.Success -> {
println("...Customer Memo successfully deleted...")
showFormattedRecord( fetchRecord.singleCustomerRecord, "Deleted" )
}
}
}
when (answer) {
1 -> displayDataSet()
2 -> displayRecord(promptTheUser("Enter a GUID to Display: "), "Current")
3 -> createRecord()
4 -> updateRecord()
5 -> deleteRecord()
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.PropertyNamingStrategy
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.httpDelete
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.fuel.httpPut
import com.github.kittinunf.result.Result
import java.time.Duration
import java.time.Instant
import java.time.LocalTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import kotlin.system.exitProcess
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Global Final Variables used throughout the program (val = Final, var = Variable)...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const val AUTH_STRING = "amNhc<blah><blah><blah>FSUkVMTDc="
const val MAIN_URL = "http://<your server>/sap/opu/odata/SAP/ZTEST_KOTLIN_SRV/ZTEST_KOTLINSet"
const val JSON_FORMAT = "?\$format=json"
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Data Class for a Fetch record, for CUD Operations...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class FetchRecord(
val CsrfToken: String,
val Cookie: String,
var singleCustomerRecord: CustomerMemoRecord
)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// A data class which represents a single Customer Memo Record from the ZTEST_KOTLIN SAP table.
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class CustomerMemoRecord(
var Guid: String = "",
var DateUpdated: String = "",
var TimeUpdated: String = "",
var LastUpdatedBy: String = "",
var OrderNumber: String = "",
var CustomerNumber: String = "",
var CustomerMessage: String = ""
)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Multiple Record GET - RootJsonNodeSet plus CustomerDataSet with all Customer Records...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
data class RootJsonNodeSet(
@JsonProperty("d")
val allRecords: CustomerDataSet
)
data class CustomerDataSet(
@JsonProperty("results")
val customerRecords: List<CustomerMemoRecord> = emptyList()
)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Single Record GET for one Customer Memo Record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
data class RootJsonNodeSingle(
@JsonProperty("d")
val singleCustomerRecord: CustomerMemoRecord
)
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method main: Entry point for the program...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
fun main() {
//Process User Selection...
var answer = 0
while (answer != 6) {
answer = displayMainMenu()
when (answer) {
1 -> displayDataSet()
2 -> displayRecord(promptTheUser("Enter a GUID to Display: "), "Current")
3 -> createRecord()
4 -> updateRecord()
5 -> deleteRecord()
6 -> {
println("\nThank you for using this amazing program!!...Goodbye...")
exitProcess(0)
}
else -> {
println()
println("Invalid Option Number. Please Enter a valid option number 1 thru 6.")
}
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method promptTheUser: Prompt the end user for something...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun promptTheUser(message: String): String {
print(message)
return readLine()!!
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method displayMainMenu: Display the user's options and prompt for input...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun displayMainMenu(): Int {
println()
println("Task Options: ")
println("(1) - Display All Data")
println("(2) - Display a Record")
println("(3) - Create a Record")
println("(4) - Update a Record")
println("(5) - Delete a Record")
println("(6) - Exit the Program")
print("Enter an Option Number: ")
var num = -1
try {
num = readLine()!!.toInt()
} catch (e: NumberFormatException) {
}
return num
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method displaySingleRecord: Display a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun displayRecord(lclGuid: String, lclTitle: String) {
val singleRecordString = "(Guid=guid'${lclGuid}')"
val lclUrl = MAIN_URL + singleRecordString + JSON_FORMAT
val fetchRecord = fetchSingleRecord(lclUrl)
showFormattedRecord( fetchRecord.singleCustomerRecord, lclTitle )
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method showFormattedRecord: Display of a single record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun showFormattedRecord(record: CustomerMemoRecord, lclTitle: String) {
println()
for (x in 0..50) print("=-") // Print 50 times for line separator...
println()
println("$lclTitle Record for Order Number ${record.OrderNumber}:")
for (x in 0..50) print("=-") // Print 50 times...
println()
println(" Guid (key): ${record.Guid}")
println(" Date Last Updated: ${jsonDateFormatter(record.DateUpdated)}")
println(" Time Last Updated: ${jsonTimeFormatter(record.TimeUpdated)}")
println("Last Updated By User: ${record.LastUpdatedBy}")
println(" Order Number: ${record.OrderNumber}")
println(" Customer Number: ${record.CustomerNumber}")
println(" Customer Memo: ${record.CustomerMessage}")
for (x in 0..50) print("=-") // Print 50 times...
println()
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method fetchSingleRecord: Fetch Data for a Single Record...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun fetchSingleRecord(lclUrl: String): FetchRecord {
val mapper = jacksonObjectMapper()
FuelManager.instance.baseHeaders = mapOf(
"Authorization" to "Basic $AUTH_STRING",
"X-CSRF-Token" to "Fetch"
)
//Ignore any properties that don't exist in our CustomerMemoRecord Class...
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val (_, response, result) = lclUrl.httpGet().responseString()
val csrfToken: String? = response.headers["x-csrf-token"].elementAt(0)
val cookie: String? = response.headers["set-cookie"].elementAt(0) + response.headers["set-cookie"].elementAt(1)
var memoRecord = CustomerMemoRecord()
when (result) {
is Result.Failure -> {
val ex = result.getException()
print(ex)
}
is Result.Success -> {
val myJsonData: RootJsonNodeSingle = mapper.readValue(result.get())
memoRecord = myJsonData.singleCustomerRecord
}
}
return FetchRecord(
CsrfToken = csrfToken.toString(),
Cookie = cookie.toString(),
singleCustomerRecord = memoRecord
)
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method displayDataSet: Display all records in the ZTEST_KOTLIN SAP table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun displayDataSet() {
println()
println("...One moment please, retrieving all records...")
FuelManager.instance.baseHeaders = mapOf("Authorization" to "Basic $AUTH_STRING")
val mapper = jacksonObjectMapper()
val url = MAIN_URL + JSON_FORMAT
//This allows you to parse out only the attributes you'd like, and ignore all others...
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
val (_, _, result) = url.httpGet().responseString()
when (result) {
is Result.Failure -> {
val ex = result.getException()
print(ex)
}
is Result.Success -> {
val myJsonData: RootJsonNodeSet = mapper.readValue(result.get())
val memoRecords: List<CustomerMemoRecord> = myJsonData.allRecords.customerRecords
println("\nTable ZTEST_KOTLIN (${memoRecords.count()} Records):")
for (x in 0..80) print("=-") // Print 80 times for line separator...
println()
println("Guid (key) " +
"| Date " +
"| Time " +
"| Updated By " +
"| Order # " +
"| Customer # " +
"| Memo")
for (x in 0..80) print("=-") // Print 80 times...
println()
memoRecords.forEach {
println(
"${it.Guid} " +
"| ${jsonDateFormatter(it.DateUpdated)} " +
"| ${jsonTimeFormatter(it.TimeUpdated)} " +
"| ${it.LastUpdatedBy.padStart(12)} " + //pad to 12 characters, to line up with column header
"| ${it.OrderNumber.padStart(10)} " + //pad to 10 characters
"| ${it.CustomerNumber.padStart(10)} " + //pad to 10 characters
"| ${it.CustomerMessage}"
)
}
for (x in 0..80) print("=-") // Print 80 times...
println()
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method createRecord: Create a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun createRecord() {
val lclOrder = promptTheUser("Enter Order Number: ")
val lclCustomer = promptTheUser("Enter Customer Number: ")
val lclMemo = promptTheUser("Enter Customer Memo: ")
//First, fetch the CSRF Token and Cookie, prior to performing the POST...
var url = MAIN_URL + JSON_FORMAT
val fetchRecord = fetchSingleRecord(url)
fetchRecord.singleCustomerRecord.OrderNumber = lclOrder
fetchRecord.singleCustomerRecord.CustomerNumber = lclCustomer
fetchRecord.singleCustomerRecord.CustomerMessage = lclMemo
//Even though we are doing a POST (Create), we still need to fill in all of the
//attributes, so enter dummy data for these ignored fields...
fetchRecord.singleCustomerRecord.Guid = "00000000-0000-0000-0000-000000000000"
fetchRecord.singleCustomerRecord.DateUpdated = """/Date(1578441600000)/"""
fetchRecord.singleCustomerRecord.LastUpdatedBy = ""
fetchRecord.singleCustomerRecord.TimeUpdated = "PT13H12M09S"
val mapper = jacksonObjectMapper()
// The default mapper, adjusts the field names to lower case camel case, but our
// Gateway service has upper case (i.e. dateUpdated vs. DateUpdated),
// so we set the UPPER_CAMEL_CASE property here...
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// Serialize the fetchRecord Object back into a JSON String and use for our POST
// to create the Customer Memo...
val jsonString = mapper.writeValueAsString(fetchRecord.singleCustomerRecord)
//Remove the "jsonFormat" URI Option, prior to doing the POST...
url = MAIN_URL
val newRecord: CustomerMemoRecord
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val postString = """{ "d" : $jsonString }"""
//This is a synchronous "Blocking Mode" call (i.e. will wait for a response)...
val (_, _, result) = url.httpPost().body(postString).responseString()
when (result) {
is Result.Failure -> {
println()
println("Post Failed...")
println(result.getException().toString() + result.error.response.toString())
}
is Result.Success -> {
val myJsonData: RootJsonNodeSingle = mapper.readValue(result.get())
newRecord = myJsonData.singleCustomerRecord
println()
println("...Customer Memo successfully created...")
displayRecord(newRecord.Guid, "New")
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method updateRecord: Update a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun updateRecord() {
val lclGuid = promptTheUser("Enter a GUID to Update: ")
val newMemo = promptTheUser("Enter the New Memo: ")
var url = "$MAIN_URL(Guid=guid'$lclGuid')$JSON_FORMAT"
val fetchRecord = fetchSingleRecord(url)
val originalMemo = fetchRecord.singleCustomerRecord.CustomerMessage
fetchRecord.singleCustomerRecord.CustomerMessage = newMemo
val mapper = jacksonObjectMapper()
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
val jsonString = mapper.writeValueAsString(fetchRecord.singleCustomerRecord)
url = "$MAIN_URL(Guid=guid'$lclGuid')"
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val putString = """{ "d" : $jsonString }"""
val (_, _, result) = url.httpPut().body(putString).responseString()
when (result) {
is Result.Failure -> {
println(result.getException().toString())
}
is Result.Success -> {
println("...Customer Memo successfully updated...")
println("Old Memo: $originalMemo")
println("New Memo: $newMemo")
displayRecord(lclGuid, "Updated")
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method deleteRecord: Delete a single record in the ZTEST_KOTLIN table...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun deleteRecord() {
val lclGuid = promptTheUser("Enter a GUID to Delete: ")
var url = "$MAIN_URL(Guid=guid'$lclGuid')$JSON_FORMAT"
val fetchRecord = fetchSingleRecord(url)
val mapper = jacksonObjectMapper()
mapper.propertyNamingStrategy = PropertyNamingStrategy.UPPER_CAMEL_CASE
url = "$MAIN_URL(Guid=guid'$lclGuid')"
initializeFuel(fetchRecord.CsrfToken, fetchRecord.Cookie)
val (_, _, result) = url.httpDelete().responseString()
when (result) {
is Result.Failure -> {
println(result.getException().toString())
}
is Result.Success -> {
println("...Customer Memo successfully deleted...")
showFormattedRecord( fetchRecord.singleCustomerRecord, "Deleted" )
}
}
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Method initializeFuel: Set the FuelManager for UPDATE or POST...
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
private fun initializeFuel(CsrfToken: String, Cookie: String) {
FuelManager.instance.baseHeaders = mapOf(
"Authorization" to "Basic $AUTH_STRING",
"X-CSRF-Token" to CsrfToken,
"cookie" to Cookie,
"Content-Type" to "application/json",
"Accept" to "application/json"
)
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method jsonDateFormatter: Parse a JSON Date (Epoch Date) into a Java/Kotlin Date
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun jsonDateFormatter(jsonDate: String): String {
val epochDate = jsonDate.replace("[^0-9]".toRegex(), "")
val updateDate = Instant.ofEpochMilli(java.lang.Long.parseLong(epochDate))
.atZone(ZoneId.of("CET"))
.toLocalDate()
return updateDate.toString()
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Method jsonTimeFormatter: Parse a JSON Time (XSD:Duration Date Type) into Java/Kotlin Time
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
private fun jsonTimeFormatter(jsonTime: String): String {
val fTime = LocalTime.ofNanoOfDay(Duration.parse(jsonTime).toNanos())
val df = DateTimeFormatter.ISO_LOCAL_TIME
return fTime.format(df)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
7 | |
5 | |
5 | |
5 | |
4 | |
4 | |
4 | |
4 | |
3 | |
3 |