[Bluetooth] Rename BluetoothGATTService to BluetoothGATTClientService 42/236842/13
authorDawid Juszczak <d.juszczak@samsung.com>
Wed, 22 Jul 2020 16:11:06 +0000 (18:11 +0200)
committerDawid Juszczak <d.juszczak@samsung.com>
Tue, 25 Aug 2020 12:55:21 +0000 (14:55 +0200)
[Verification] Each method implemented by BluetoothGATTClientService was
called in Chrome Dev Tools.
All auto Bluetooth and manual BLE tests pass.

Change-Id: I530e94aa40b294d43525aed50c9a19dde3c2a1c4
Signed-off-by: Dawid Juszczak <d.juszczak@samsung.com>
Signed-off-by: Pawel Wasowski <p.wasowski2@samsung.com>
src/bluetooth/bluetooth.gyp
src/bluetooth/bluetooth_api.js
src/bluetooth/bluetooth_gatt_client_service.cc [new file with mode: 0644]
src/bluetooth/bluetooth_gatt_client_service.h [new file with mode: 0644]
src/bluetooth/bluetooth_gatt_service.cc [deleted file]
src/bluetooth/bluetooth_gatt_service.h [deleted file]
src/bluetooth/bluetooth_instance.cc
src/bluetooth/bluetooth_instance.h
src/bluetooth/bluetooth_le_device.cc
src/bluetooth/bluetooth_le_device.h
src/bluetooth/uuid.h

index 73df5d3f5948d8cbe956fe3788aca932142ecac5..f99eb6b7cef70fa72ea703f2d244b2a4ace15901 100644 (file)
@@ -33,8 +33,8 @@
         'bluetooth_le_adapter.h',
         'bluetooth_service_handler.cc',
         'bluetooth_service_handler.h',
-        'bluetooth_gatt_service.cc',
-        'bluetooth_gatt_service.h',
+        'bluetooth_gatt_client_service.cc',
+        'bluetooth_gatt_client_service.h',
         'bluetooth_socket.cc',
         'bluetooth_socket.h',
         'bluetooth_util.cc',
index 37799e0032ec0a2d01695405f8eabd3f7063c46f..df42559ab513038d36e32ad7a6b18263aa58635a 100755 (executable)
@@ -1621,7 +1621,7 @@ var BluetoothGATTService = function(data, address) {
     var address_ = address || data.address;
     function servicesGetter() {
         var services = [];
-        var result = native.callSync('BluetoothGATTServiceGetServices', {
+        var result = native.callSync('BluetoothGATTClientServiceGetServices', {
             handle: handle_,
             address: address_
         });
@@ -1635,7 +1635,7 @@ var BluetoothGATTService = function(data, address) {
     }
     function characteristicsGetter() {
         var characteristics = [];
-        var result = native.callSync('BluetoothGATTServiceGetCharacteristics', {
+        var result = native.callSync('BluetoothGATTClientServiceGetCharacteristics', {
             handle: handle_,
             uuid: serviceUuid_,
             address: address_
@@ -1790,7 +1790,7 @@ var BluetoothGATTCharacteristic = function(data, address) {
 
         var callArgs = { handle: handle_, address: address_ };
 
-        var result = native.call('BluetoothGATTServiceReadValue', callArgs, callback);
+        var result = native.call('BluetoothGATTClientServiceReadValue', callArgs, callback);
 
         if (native.isFailure(result)) {
             throw native.getErrorObject(result);
@@ -1828,7 +1828,7 @@ var BluetoothGATTCharacteristic = function(data, address) {
             address: address_
         };
 
-        var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback);
+        var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback);
 
         if (native.isFailure(result)) {
             throw native.getErrorObject(result);
@@ -1985,8 +1985,8 @@ var _bluetoothGATTCharacteristicListener = _multipleListenerBuilder(
     function(listener, event) {
         listener(event);
     },
-    'BluetoothGATTServiceAddValueChangeListener',
-    'BluetoothGATTServiceRemoveValueChangeListener',
+    'BluetoothGATTClientServiceAddValueChangeListener',
+    'BluetoothGATTClientServiceRemoveValueChangeListener',
     true
 );
 
@@ -2032,7 +2032,7 @@ var BluetoothGATTDescriptor = function(data, address) {
 
         var callArgs = { handle: handle_, address: address_ };
 
-        var result = native.call('BluetoothGATTServiceReadValue', callArgs, callback);
+        var result = native.call('BluetoothGATTClientServiceReadValue', callArgs, callback);
 
         if (native.isFailure(result)) {
             throw native.getErrorObject(result);
@@ -2070,7 +2070,7 @@ var BluetoothGATTDescriptor = function(data, address) {
             address: address_
         };
 
-        var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback);
+        var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback);
 
         if (native.isFailure(result)) {
             throw native.getErrorObject(result);
diff --git a/src/bluetooth/bluetooth_gatt_client_service.cc b/src/bluetooth/bluetooth_gatt_client_service.cc
new file mode 100644 (file)
index 0000000..1be096c
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed 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.
+ */
+
+#include "bluetooth/bluetooth_gatt_client_service.h"
+
+#include <sstream>
+
+#include "common/extension.h"
+#include "common/logger.h"
+#include "common/platform_result.h"
+#include "common/task-queue.h"
+#include "common/tools.h"
+
+#include "bluetooth/bluetooth_instance.h"
+#include "bluetooth/bluetooth_privilege.h"
+#include "bluetooth/bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using common::PlatformResult;
+using common::ErrorCode;
+using common::TaskQueue;
+using namespace common::tools;
+
+namespace {
+const std::string kUuid = "uuid";
+const std::string kServiceUuid = "serviceUuid";
+const std::string kHandle = "handle";
+const std::string kAddress = "address";
+
+const std::string kDescriptors = "descriptors";
+const std::string kBroadcast = "isBroadcast";
+const std::string kExtendedProperties = "hasExtendedProperties";
+const std::string kNotify = "isNotify";
+const std::string kIndication = "isIndication";
+const std::string kReadable = "isReadable";
+const std::string kSignedWrite = "isSignedWrite";
+const std::string kWritable = "isWritable";
+const std::string kWriteNoResponse = "isWriteNoResponse";
+
+const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener";
+
+bool IsProperty(int propertyBits, bt_gatt_property_e property) {
+  return (propertyBits & property) != 0;
+}
+}
+
+BluetoothGATTClientService::BluetoothGATTClientService(BluetoothInstance& instance) : instance_(instance) {
+  ScopeLogger();
+}
+
+BluetoothGATTClientService::~BluetoothGATTClientService() {
+  ScopeLogger();
+
+  for (auto it : gatt_characteristic_) {
+    // unregister callback, ignore errors
+    bt_gatt_client_unset_characteristic_value_changed_cb(it);
+  }
+
+  for (auto it : gatt_clients_) {
+    LoggerD("destroying client for address: %s", it.first.c_str());
+    bt_gatt_client_destroy(it.second);
+  }
+}
+
+bool BluetoothGATTClientService::IsStillConnected(const std::string& address) {
+  auto it = gatt_clients_.find(address);
+  return gatt_clients_.end() != it;
+}
+
+bt_gatt_client_h BluetoothGATTClientService::GetGattClient(const std::string& address) {
+  ScopeLogger();
+
+  bt_gatt_client_h client = nullptr;
+
+  const auto it = gatt_clients_.find(address);
+
+  if (gatt_clients_.end() == it) {
+    int ret = bt_gatt_client_create(address.c_str(), &client);
+    if (BT_ERROR_NONE != ret) {
+      LoggerE("Failed to create GATT client, error: %d", ret);
+    } else {
+      gatt_clients_.insert(std::make_pair(address, client));
+    }
+  } else {
+    LoggerD("Client already created");
+    client = it->second;
+  }
+
+  return client;
+}
+
+// this method should be used to inform this object that some device was disconnected
+void BluetoothGATTClientService::TryDestroyClient(const std::string& address) {
+  ScopeLogger();
+  auto it = gatt_clients_.find(address);
+  if (gatt_clients_.end() != it) {
+    LoggerD("destroying client for address: %s", it->first.c_str());
+    bt_gatt_client_destroy(it->second);
+    gatt_clients_.erase(it);
+  } else {
+    LoggerD("Client for address: %s does not exist, no need for deletion", address.c_str());
+  }
+}
+
+PlatformResult BluetoothGATTClientService::GetSpecifiedGATTClient(const std::string& address,
+                                                             const UUID& uuid,
+                                                             picojson::object* result) {
+  ScopeLogger();
+
+  bt_gatt_client_h client = GetGattClient(address);
+
+  if (nullptr == client) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to create the GATT client's handle");
+  }
+
+  bt_gatt_h service = nullptr;
+  int ret = bt_gatt_client_get_service(client, uuid.uuid_128_bit.c_str(), &service);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("bt_gatt_client_get_service() error: %d", ret);
+    switch (ret) {
+      case BT_ERROR_NO_DATA:
+        return LogAndCreateResult(
+            ErrorCode::NOT_FOUND_ERR, "Service not found",
+            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
+
+      case BT_ERROR_INVALID_PARAMETER:
+        return LogAndCreateResult(
+            ErrorCode::NOT_FOUND_ERR, "Service UUID is invalid",
+            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
+
+      default:
+        return LogAndCreateResult(
+            ErrorCode::UNKNOWN_ERR, "Failed to get a service's GATT handle",
+            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
+    }
+  }
+
+  /*
+   * BACKWARD COMPATIBILITY
+   *
+   * BluetoothGATTClientService::uuid has always been set to source format in this
+   * function.
+   */
+  result->insert(std::make_pair(kUuid, picojson::value(uuid.uuid_in_source_format)));
+  result->insert(std::make_pair(kServiceUuid, picojson::value(uuid.uuid_in_source_format)));
+  // handle is passed to upper layer because there is no need to delete it
+  result->insert(std::make_pair(kHandle, picojson::value((double)(long)service)));
+  // address is necessary to later check if device is still connected
+  result->insert(std::make_pair(kAddress, picojson::value(address)));
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void BluetoothGATTClientService::GetServices(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
+  const std::string& address = args.get("address").get<std::string>();
+
+  picojson::array array;
+  PlatformResult ret = GetServicesHelper(handle, address, &array);
+  if (ret.IsError()) {
+    LogAndReportError(ret, &out, ("Error while getting services"));
+  } else {
+    ReportSuccess(picojson::value(array), out);
+  }
+}
+
+PlatformResult BluetoothGATTClientService::GetServicesHelper(bt_gatt_h handle, const std::string& address,
+                                                       picojson::array* array) {
+  ScopeLogger();
+
+  if (!IsStillConnected(address)) {
+    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected",
+                              ("Device with address %s is no longer connected", address.c_str()));
+  }
+
+  int ret = bt_gatt_service_foreach_included_services(
+      handle,
+      [](int total, int index, bt_gatt_h gatt_handle, void* data) {
+        ScopeLogger(
+            "Entered into asynchronous function, argument in "
+            "bt_gatt_service_foreach_included_services");
+
+        picojson::value result = picojson::value{picojson::object{}};
+        picojson::object& result_obj = result.get<picojson::object>();
+
+        const auto uuid = UUID::createFromGatt(gatt_handle);
+        if (uuid) {
+          /*
+           * BACKWARD COMPATIBILITY
+           *
+           * UUID has always been set to source format in this function.
+           */
+          result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->uuid_in_source_format}));
+          result_obj.insert(std::make_pair(kServiceUuid, picojson::value{uuid->uuid_in_source_format}));
+        } else {
+          result_obj.insert(std::make_pair(kUuid, picojson::value{"0xFFFF"}));
+          result_obj.insert(std::make_pair(kServiceUuid, picojson::value{}));
+        }
+
+        // handle is passed to upper layer because there is no need of deletion
+        result_obj.insert(std::make_pair(kHandle, picojson::value{(double)(long)gatt_handle}));
+        static_cast<picojson::array*>(data)->push_back(result);
+        return true;
+      },
+      array);
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("Failed bt_gatt_service_foreach_included_services() (%d)", ret);
+    return util::GetBluetoothError(ret, "Failed to set a service's GATT callback");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void BluetoothGATTClientService::GetCharacteristics(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+
+  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
+
+  const std::string& address = args.get("address").get<std::string>();
+
+  picojson::array array;
+  PlatformResult ret = GetCharacteristicsHelper(handle, address, &array);
+  if (ret.IsError()) {
+    LogAndReportError(ret, &out, ("Error while getting characteristics"));
+  } else {
+    ReportSuccess(picojson::value(array), out);
+  }
+}
+
+PlatformResult BluetoothGATTClientService::GetCharacteristicsHelper(bt_gatt_h handle,
+                                                              const std::string& address,
+                                                              picojson::array* array) {
+  ScopeLogger();
+
+  if (!IsStillConnected(address)) {
+    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected",
+                              ("Device with address %s is no longer connected", address.c_str()));
+  }
+
+  struct Data {
+    picojson::array* array;
+    PlatformResult* platform_res;
+  };
+
+  PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR);
+  Data user_data = {array, &platform_result};
+
+  int ret = bt_gatt_service_foreach_characteristics(
+      handle,
+      [](int total, int index, bt_gatt_h gatt_handle, void* data) {
+        ScopeLogger(
+            "Entered into asynchronous function, bt_gatt_service_foreach_characteristics;"
+            " index: %d", index);
+        Data* user_data = static_cast<Data*>(data);
+        picojson::array* array = user_data->array;
+        PlatformResult* platform_result = user_data->platform_res;
+
+        picojson::value result = picojson::value(picojson::object());
+        picojson::object& result_obj = result.get<picojson::object>();
+
+        // handle is passed to upper layer because there is no need of deletion
+        result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)gatt_handle)));
+
+        // descriptors
+        picojson::array& desc_array =
+            result_obj.insert(std::make_pair("descriptors", picojson::value(picojson::array())))
+                .first->second.get<picojson::array>();
+        int ret = bt_gatt_characteristic_foreach_descriptors(
+            gatt_handle,
+            [](int total, int index, bt_gatt_h desc_handle, void* data) {
+              ScopeLogger(
+                "Entered into asynchronous function, bt_gatt_characteristic_foreach_descriptors;"
+                " index: %d", index);
+              picojson::array& desc_array = *(static_cast<picojson::array*>(data));
+
+              picojson::value desc = picojson::value(picojson::object());
+              picojson::object& desc_obj = desc.get<picojson::object>();
+
+              // handle is passed to upper layer because there is no need of deletion
+              desc_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)desc_handle)));
+
+              auto uuid = UUID::createFromGatt(desc_handle);
+              if (uuid) {
+                desc_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()}));
+              } else {
+                desc_obj.insert(std::make_pair(kUuid, picojson::value{}));
+              }
+
+              desc_array.push_back(desc);
+              return true;
+            },
+            static_cast<void*>(&desc_array));
+        if (BT_ERROR_NONE != ret) {
+          *platform_result = util::GetBluetoothError(ret, "Failed to get descriptors");
+          LoggerE("Failed bt_gatt_characteristic_foreach_descriptors() (%d)", ret);
+          return false;
+        }
+
+        // other properties
+        int property_bits = 0;
+        int err = bt_gatt_characteristic_get_properties(gatt_handle, &property_bits);
+        if (BT_ERROR_NONE != err) {
+          LoggerE("Properties of characteristic couldn't be acquired");
+        }
+        result_obj.insert(std::make_pair(
+            kBroadcast, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_BROADCAST))));
+        result_obj.insert(std::make_pair(
+            kReadable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_READ))));
+        result_obj.insert(std::make_pair(
+            kWriteNoResponse,
+            picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE))));
+        result_obj.insert(std::make_pair(
+            kWritable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE))));
+        result_obj.insert(std::make_pair(
+            kNotify, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_NOTIFY))));
+        result_obj.insert(std::make_pair(
+            kIndication, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_INDICATE))));
+        result_obj.insert(std::make_pair(
+            kSignedWrite, picojson::value(IsProperty(
+                              property_bits, BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES))));
+        result_obj.insert(std::make_pair(
+            kExtendedProperties,
+            picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_EXTENDED_PROPERTIES))));
+
+        auto uuid = UUID::createFromGatt(gatt_handle);
+        if (uuid) {
+          result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()}));
+        } else {
+          LoggerW("bt_gatt_get_uuid error: %d (%s)", err, get_error_message(err));
+          result_obj.insert(std::make_pair(kUuid, picojson::value{}));
+        }
+
+        array->push_back(result);
+        return true;
+      },
+      static_cast<void*>(&user_data));
+  if (platform_result.IsError()) {
+    return platform_result;
+  }
+  if (BT_ERROR_NONE != ret) {
+    LoggerE("Failed (%d)", ret);
+    return util::GetBluetoothError(ret, "Failed while getting characteristic");
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void BluetoothGATTClientService::ReadValue(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
+                                              &out);
+
+  const std::string& address = args.get("address").get<std::string>();
+  if (!IsStillConnected(address)) {
+    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
+                      ("Device with address %s is no longer connected", address.c_str()));
+    return;
+  }
+
+  const double callback_handle = util::GetAsyncCallbackHandle(args);
+  struct Data {
+    double callback_handle;
+    BluetoothGATTClientService* service;
+  };
+
+  Data* user_data = new Data{callback_handle, this};
+  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
+
+  auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
+    ScopeLogger("Entered into asynchronous function, read_value");
+    Data* data = static_cast<Data*>(user_data);
+    double callback_handle = data->callback_handle;
+    BluetoothGATTClientService* service = data->service;
+    delete data;
+
+    PlatformResult plarform_res = PlatformResult(ErrorCode::NO_ERROR);
+
+    picojson::value byte_array = picojson::value(picojson::array());
+    picojson::array& byte_array_obj = byte_array.get<picojson::array>();
+
+    if (BT_ERROR_NONE != result) {
+      plarform_res = util::GetBluetoothError(result, "Error while reading value");
+    } else {
+      char* value = nullptr;
+      int length = 0;
+      int ret = bt_gatt_get_value(handle, &value, &length);
+      if (BT_ERROR_NONE != ret) {
+        plarform_res = util::GetBluetoothError(ret, "Error while getting value");
+      } else {
+        for (int i = 0; i < length; i++) {
+          byte_array_obj.push_back(picojson::value(std::to_string(value[i])));
+        }
+      }
+      if (value) {
+        free(value);
+        value = nullptr;
+      }
+    }
+
+    std::shared_ptr<picojson::value> response =
+        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+    if (plarform_res.IsSuccess()) {
+      ReportSuccess(byte_array, response->get<picojson::object>());
+    } else {
+      LogAndReportError(plarform_res, &response->get<picojson::object>());
+    }
+    TaskQueue::GetInstance().Async<picojson::value>(
+        [service, callback_handle](const std::shared_ptr<picojson::value>& response) {
+          service->instance_.SyncResponse(callback_handle, response);
+        },
+        response);
+  };
+  int ret = bt_gatt_client_read_value(handle, read_value, (void*)user_data);
+  if (BT_ERROR_NONE != ret) {
+    delete user_data;
+    user_data = nullptr;
+    LoggerE("Couldn't register callback for read value %d (%s)", ret, get_error_message(ret));
+  }
+  ReportSuccess(out);
+}
+
+void BluetoothGATTClientService::WriteValue(const picojson::value& args, picojson::object& out) {
+  ScopeLogger();
+  CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
+                                              &out);
+
+  const std::string& address = args.get("address").get<std::string>();
+  if (!IsStillConnected(address)) {
+    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
+                      ("Device with address %s is no longer connected", address.c_str()));
+    return;
+  }
+
+  const double callback_handle = util::GetAsyncCallbackHandle(args);
+  const picojson::array& value_array = args.get("value").get<picojson::array>();
+
+  int value_size = value_array.size();
+  std::unique_ptr<char[]> value_data(new char[value_size]);
+  for (int i = 0; i < value_size; ++i) {
+    value_data[i] = (int)value_array[i].get<double>();
+  }
+
+  struct Data {
+    double callback_handle;
+    BluetoothGATTClientService* service;
+  };
+
+  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
+
+  auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
+    ScopeLogger("Entered into asynchronous function, write_value");
+    Data* data = static_cast<Data*>(user_data);
+    double callback_handle = data->callback_handle;
+    BluetoothGATTClientService* service = data->service;
+    delete data;
+
+    PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
+    if (BT_ERROR_NONE != result) {
+      ret = util::GetBluetoothError(result, "Error while getting value");
+    }
+
+    std::shared_ptr<picojson::value> response =
+        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+    if (ret.IsSuccess()) {
+      ReportSuccess(response->get<picojson::object>());
+    } else {
+      LogAndReportError(ret, &response->get<picojson::object>());
+    }
+    TaskQueue::GetInstance().Async<picojson::value>(
+        [service, callback_handle](const std::shared_ptr<picojson::value>& response) {
+          service->instance_.SyncResponse(callback_handle, response);
+        },
+        response);
+  };
+
+  int ret = bt_gatt_set_value(handle, value_data.get(), value_size);
+
+  if (BT_ERROR_NONE != ret) {
+    std::shared_ptr<picojson::value> response =
+        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+    LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"),
+                      &response->get<picojson::object>(),
+                      ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret)));
+    TaskQueue::GetInstance().Async<picojson::value>(
+        [this, callback_handle](const std::shared_ptr<picojson::value>& response) {
+          instance_.SyncResponse(callback_handle, response);
+        },
+        response);
+  } else {
+    Data* user_data = new Data{callback_handle, this};
+    ret = bt_gatt_client_write_value(handle, write_value, user_data);
+    if (BT_ERROR_NONE != ret) {
+      delete user_data;
+      LoggerE("Couldn't register callback for write value %d (%s)", ret, get_error_message(ret));
+    }
+  }
+  ReportSuccess(out);
+}
+
+void BluetoothGATTClientService::AddValueChangeListener(const picojson::value& args,
+                                                  picojson::object& out) {
+  ScopeLogger();
+  const auto& address = args.get("address").get<std::string>();
+  if (!IsStillConnected(address)) {
+    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
+                      ("Device with address %s is no longer connected", address.c_str()));
+    return;
+  }
+
+  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get(kHandle).get<double>());
+
+  int ret = bt_gatt_client_set_characteristic_value_changed_cb(handle, OnCharacteristicValueChanged,
+                                                               this);
+  if (BT_ERROR_NONE != ret) {
+    LogAndReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out,
+                      ("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d (%s)",
+                       ret, get_error_message(ret)));
+  } else {
+    gatt_characteristic_.push_back(handle);
+    ReportSuccess(out);
+  }
+}
+
+void BluetoothGATTClientService::RemoveValueChangeListener(const picojson::value& args,
+                                                     picojson::object& out) {
+  ScopeLogger();
+  const auto& address = args.get("address").get<std::string>();
+  if (!IsStillConnected(address)) {
+    LoggerW("Device with address %s is no longer connected", address.c_str());
+  } else {
+    bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get(kHandle).get<double>());
+
+    int ret = bt_gatt_client_unset_characteristic_value_changed_cb(handle);
+
+    if (BT_ERROR_NONE != ret) {
+      LoggerW("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d (%s)", ret,
+              get_error_message(ret));
+    } else {
+      gatt_characteristic_.erase(
+          std::remove(gatt_characteristic_.begin(), gatt_characteristic_.end(), handle),
+          gatt_characteristic_.end());
+    }
+  }
+  ReportSuccess(out);
+}
+
+common::PlatformResult BluetoothGATTClientService::GetServiceAllUuids(const std::string& address,
+                                                                picojson::array* array) {
+  ScopeLogger();
+
+  bt_gatt_client_h client = GetGattClient(address);
+
+  if (nullptr == client) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to create client");
+  }
+
+  auto foreach_callback = [](int total, int index, bt_gatt_h gatt_handle, void* user_data) -> bool {
+    ScopeLogger("Entered into asynchronous function, foreach_callback, total: %d, index: %d", total,
+                index);
+
+    auto& uuids = *static_cast<picojson::array*>(user_data);
+    auto uuid = UUID::createFromGatt(gatt_handle);
+    if (uuid) {
+      /*
+       * BACKWARD COMPATIBILITY
+       *
+       * In the past, this function has always trimmed UUIDs retrieved
+       * from native API to 16 bit format. UUIDs that were not created
+       * from 16 bit UUID and BASE_UUID were converted to invalid values.
+       *
+       * We return UUIDs in shortest possible format to comply with past
+       * behaviour when possible. If the UUID is not convertible
+       * to 16 bit UUID, we return a longer form.
+       */
+      uuids.push_back(picojson::value{uuid->ShortestPossibleFormat()});
+    } else {
+      LoggerE("Couldn't get UUID from bt_gatt_h");
+    }
+
+    return true;
+  };
+
+  int ret = bt_gatt_client_foreach_services(client, foreach_callback, array);
+
+  if (BT_ERROR_NONE == ret) {
+    return PlatformResult(ErrorCode::NO_ERROR);
+  } else {
+    return util::GetBluetoothError(ret, "Failed to get UUIDS");
+  }
+}
+
+void BluetoothGATTClientService::OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value,
+                                                        int length, void* user_data) {
+  ScopeLogger("characteristic: [%p], len: [%d], user_data: [%p]", characteristic, length,
+              user_data);
+
+  auto service = static_cast<BluetoothGATTClientService*>(user_data);
+
+  if (!service) {
+    LoggerE("user_data is NULL");
+    return;
+  }
+
+  picojson::value result = picojson::value(picojson::object());
+  picojson::object& result_obj = result.get<picojson::object>();
+
+  result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)characteristic)));
+
+  picojson::value byte_array = picojson::value(picojson::array());
+  picojson::array& byte_array_obj = byte_array.get<picojson::array>();
+
+  for (int i = 0; i < length; ++i) {
+    byte_array_obj.push_back(picojson::value(std::to_string(value[i])));
+  }
+
+  ReportSuccess(byte_array, result_obj);
+
+  service->instance_.FireEvent(kOnValueChanged, result);
+}
+
+}  // namespace bluetooth
+}  // namespace extension
diff --git a/src/bluetooth/bluetooth_gatt_client_service.h b/src/bluetooth/bluetooth_gatt_client_service.h
new file mode 100644 (file)
index 0000000..7232868
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed 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.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_
+#define BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_
+
+#include <map>
+
+#include <bluetooth.h>
+
+#include "bluetooth/uuid.h"
+#include "common/picojson.h"
+#include "common/platform_result.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothInstance;
+
+class BluetoothGATTClientService {
+ public:
+  BluetoothGATTClientService(BluetoothInstance& instance);
+  ~BluetoothGATTClientService();
+
+  common::PlatformResult GetSpecifiedGATTClient(const std::string& address, const UUID& uuid,
+                                                 picojson::object* result);
+
+  void TryDestroyClient(const std::string& address);
+  void GetServices(const picojson::value& data, picojson::object& out);
+  void GetCharacteristics(const picojson::value& data, picojson::object& out);
+  void ReadValue(const picojson::value& args, picojson::object& out);
+  void WriteValue(const picojson::value& args, picojson::object& out);
+  void AddValueChangeListener(const picojson::value& args, picojson::object& out);
+  void RemoveValueChangeListener(const picojson::value& args, picojson::object& out);
+
+  common::PlatformResult GetServiceAllUuids(const std::string& address, picojson::array* array);
+
+ private:
+  bool IsStillConnected(const std::string& address);
+
+  bt_gatt_client_h GetGattClient(const std::string& address);
+
+  common::PlatformResult GetServicesHelper(bt_gatt_h handle, const std::string& address,
+                                           picojson::array* array);
+  common::PlatformResult GetCharacteristicsHelper(bt_gatt_h handle, const std::string& address,
+                                                  picojson::array* array);
+
+  static void OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, int len,
+                                           void* user_data);
+
+  std::map<std::string, bt_gatt_client_h> gatt_clients_;
+  std::vector<bt_gatt_h> gatt_characteristic_;
+
+  BluetoothInstance& instance_;
+};
+
+}  // namespace bluetooth
+}  // namespace extension
+
+#endif  // BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_
diff --git a/src/bluetooth/bluetooth_gatt_service.cc b/src/bluetooth/bluetooth_gatt_service.cc
deleted file mode 100644 (file)
index ca74a24..0000000
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *    Licensed 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.
- */
-
-#include "bluetooth/bluetooth_gatt_service.h"
-
-#include <sstream>
-
-#include "common/extension.h"
-#include "common/logger.h"
-#include "common/platform_result.h"
-#include "common/task-queue.h"
-#include "common/tools.h"
-
-#include "bluetooth/bluetooth_instance.h"
-#include "bluetooth/bluetooth_privilege.h"
-#include "bluetooth/bluetooth_util.h"
-
-namespace extension {
-namespace bluetooth {
-
-using common::PlatformResult;
-using common::ErrorCode;
-using common::TaskQueue;
-using namespace common::tools;
-
-namespace {
-const std::string kUuid = "uuid";
-const std::string kServiceUuid = "serviceUuid";
-const std::string kHandle = "handle";
-const std::string kAddress = "address";
-
-const std::string kDescriptors = "descriptors";
-const std::string kBroadcast = "isBroadcast";
-const std::string kExtendedProperties = "hasExtendedProperties";
-const std::string kNotify = "isNotify";
-const std::string kIndication = "isIndication";
-const std::string kReadable = "isReadable";
-const std::string kSignedWrite = "isSignedWrite";
-const std::string kWritable = "isWritable";
-const std::string kWriteNoResponse = "isWriteNoResponse";
-
-const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener";
-
-bool IsProperty(int propertyBits, bt_gatt_property_e property) {
-  return (propertyBits & property) != 0;
-}
-}
-
-BluetoothGATTService::BluetoothGATTService(BluetoothInstance& instance) : instance_(instance) {
-  ScopeLogger();
-}
-
-BluetoothGATTService::~BluetoothGATTService() {
-  ScopeLogger();
-
-  for (auto it : gatt_characteristic_) {
-    // unregister callback, ignore errors
-    bt_gatt_client_unset_characteristic_value_changed_cb(it);
-  }
-
-  for (auto it : gatt_clients_) {
-    LoggerD("destroying client for address: %s", it.first.c_str());
-    bt_gatt_client_destroy(it.second);
-  }
-}
-
-bool BluetoothGATTService::IsStillConnected(const std::string& address) {
-  auto it = gatt_clients_.find(address);
-  return gatt_clients_.end() != it;
-}
-
-bt_gatt_client_h BluetoothGATTService::GetGattClient(const std::string& address) {
-  ScopeLogger();
-
-  bt_gatt_client_h client = nullptr;
-
-  const auto it = gatt_clients_.find(address);
-
-  if (gatt_clients_.end() == it) {
-    int ret = bt_gatt_client_create(address.c_str(), &client);
-    if (BT_ERROR_NONE != ret) {
-      LoggerE("Failed to create GATT client, error: %d", ret);
-    } else {
-      gatt_clients_.insert(std::make_pair(address, client));
-    }
-  } else {
-    LoggerD("Client already created");
-    client = it->second;
-  }
-
-  return client;
-}
-
-// this method should be used to inform this object that some device was disconnected
-void BluetoothGATTService::TryDestroyClient(const std::string& address) {
-  ScopeLogger();
-  auto it = gatt_clients_.find(address);
-  if (gatt_clients_.end() != it) {
-    LoggerD("destroying client for address: %s", it->first.c_str());
-    bt_gatt_client_destroy(it->second);
-    gatt_clients_.erase(it);
-  } else {
-    LoggerD("Client for address: %s does not exist, no need for deletion", address.c_str());
-  }
-}
-
-PlatformResult BluetoothGATTService::GetSpecifiedGATTService(const std::string& address,
-                                                             const UUID& uuid,
-                                                             picojson::object* result) {
-  ScopeLogger();
-
-  bt_gatt_client_h client = GetGattClient(address);
-
-  if (nullptr == client) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to create the GATT client's handle");
-  }
-
-  bt_gatt_h service = nullptr;
-  int ret = bt_gatt_client_get_service(client, uuid.uuid_128_bit.c_str(), &service);
-  if (BT_ERROR_NONE != ret) {
-    LoggerE("bt_gatt_client_get_service() error: %d", ret);
-    switch (ret) {
-      case BT_ERROR_NO_DATA:
-        return LogAndCreateResult(
-            ErrorCode::NOT_FOUND_ERR, "Service not found",
-            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
-
-      case BT_ERROR_INVALID_PARAMETER:
-        return LogAndCreateResult(
-            ErrorCode::NOT_FOUND_ERR, "Service UUID is invalid",
-            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
-
-      default:
-        return LogAndCreateResult(
-            ErrorCode::UNKNOWN_ERR, "Failed to get a service's GATT handle",
-            ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret)));
-    }
-  }
-
-  /*
-   * BACKWARD COMPATIBILITY
-   *
-   * BluetoothGATTService::uuid has always been set to source format in this
-   * function.
-   */
-  result->insert(std::make_pair(kUuid, picojson::value(uuid.uuid_in_source_format)));
-  result->insert(std::make_pair(kServiceUuid, picojson::value(uuid.uuid_in_source_format)));
-  // handle is passed to upper layer because there is no need to delete it
-  result->insert(std::make_pair(kHandle, picojson::value((double)(long)service)));
-  // address is necessary to later check if device is still connected
-  result->insert(std::make_pair(kAddress, picojson::value(address)));
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-void BluetoothGATTService::GetServices(const picojson::value& args, picojson::object& out) {
-  ScopeLogger();
-
-  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
-  const std::string& address = args.get("address").get<std::string>();
-
-  picojson::array array;
-  PlatformResult ret = GetServicesHelper(handle, address, &array);
-  if (ret.IsError()) {
-    LogAndReportError(ret, &out, ("Error while getting services"));
-  } else {
-    ReportSuccess(picojson::value(array), out);
-  }
-}
-
-PlatformResult BluetoothGATTService::GetServicesHelper(bt_gatt_h handle, const std::string& address,
-                                                       picojson::array* array) {
-  ScopeLogger();
-
-  if (!IsStillConnected(address)) {
-    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected",
-                              ("Device with address %s is no longer connected", address.c_str()));
-  }
-
-  int ret = bt_gatt_service_foreach_included_services(
-      handle,
-      [](int total, int index, bt_gatt_h gatt_handle, void* data) {
-        ScopeLogger(
-            "Entered into asynchronous function, argument in "
-            "bt_gatt_service_foreach_included_services");
-
-        picojson::value result = picojson::value{picojson::object{}};
-        picojson::object& result_obj = result.get<picojson::object>();
-
-        const auto uuid = UUID::createFromGatt(gatt_handle);
-        if (uuid) {
-          /*
-           * BACKWARD COMPATIBILITY
-           *
-           * UUID has always been set to source format in this function.
-           */
-          result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->uuid_in_source_format}));
-          result_obj.insert(std::make_pair(kServiceUuid, picojson::value{uuid->uuid_in_source_format}));
-        } else {
-          result_obj.insert(std::make_pair(kUuid, picojson::value{"0xFFFF"}));
-          result_obj.insert(std::make_pair(kServiceUuid, picojson::value{}));
-        }
-
-        // handle is passed to upper layer because there is no need of deletion
-        result_obj.insert(std::make_pair(kHandle, picojson::value{(double)(long)gatt_handle}));
-        static_cast<picojson::array*>(data)->push_back(result);
-        return true;
-      },
-      array);
-  if (BT_ERROR_NONE != ret) {
-    LoggerE("Failed bt_gatt_service_foreach_included_services() (%d)", ret);
-    return util::GetBluetoothError(ret, "Failed to set a service's GATT callback");
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-void BluetoothGATTService::GetCharacteristics(const picojson::value& args, picojson::object& out) {
-  ScopeLogger();
-
-  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
-
-  const std::string& address = args.get("address").get<std::string>();
-
-  picojson::array array;
-  PlatformResult ret = GetCharacteristicsHelper(handle, address, &array);
-  if (ret.IsError()) {
-    LogAndReportError(ret, &out, ("Error while getting characteristics"));
-  } else {
-    ReportSuccess(picojson::value(array), out);
-  }
-}
-
-PlatformResult BluetoothGATTService::GetCharacteristicsHelper(bt_gatt_h handle,
-                                                              const std::string& address,
-                                                              picojson::array* array) {
-  ScopeLogger();
-
-  if (!IsStillConnected(address)) {
-    return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected",
-                              ("Device with address %s is no longer connected", address.c_str()));
-  }
-
-  struct Data {
-    picojson::array* array;
-    PlatformResult* platform_res;
-  };
-
-  PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR);
-  Data user_data = {array, &platform_result};
-
-  int ret = bt_gatt_service_foreach_characteristics(
-      handle,
-      [](int total, int index, bt_gatt_h gatt_handle, void* data) {
-        ScopeLogger(
-            "Entered into asynchronous function, bt_gatt_service_foreach_characteristics;"
-            " index: %d", index);
-        Data* user_data = static_cast<Data*>(data);
-        picojson::array* array = user_data->array;
-        PlatformResult* platform_result = user_data->platform_res;
-
-        picojson::value result = picojson::value(picojson::object());
-        picojson::object& result_obj = result.get<picojson::object>();
-
-        // handle is passed to upper layer because there is no need of deletion
-        result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)gatt_handle)));
-
-        // descriptors
-        picojson::array& desc_array =
-            result_obj.insert(std::make_pair("descriptors", picojson::value(picojson::array())))
-                .first->second.get<picojson::array>();
-        int ret = bt_gatt_characteristic_foreach_descriptors(
-            gatt_handle,
-            [](int total, int index, bt_gatt_h desc_handle, void* data) {
-              ScopeLogger(
-                "Entered into asynchronous function, bt_gatt_characteristic_foreach_descriptors;"
-                " index: %d", index);
-              picojson::array& desc_array = *(static_cast<picojson::array*>(data));
-
-              picojson::value desc = picojson::value(picojson::object());
-              picojson::object& desc_obj = desc.get<picojson::object>();
-
-              // handle is passed to upper layer because there is no need of deletion
-              desc_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)desc_handle)));
-
-              auto uuid = UUID::createFromGatt(desc_handle);
-              if (uuid) {
-                desc_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()}));
-              } else {
-                desc_obj.insert(std::make_pair(kUuid, picojson::value{}));
-              }
-
-              desc_array.push_back(desc);
-              return true;
-            },
-            static_cast<void*>(&desc_array));
-        if (BT_ERROR_NONE != ret) {
-          *platform_result = util::GetBluetoothError(ret, "Failed to get descriptors");
-          LoggerE("Failed bt_gatt_characteristic_foreach_descriptors() (%d)", ret);
-          return false;
-        }
-
-        // other properties
-        int property_bits = 0;
-        int err = bt_gatt_characteristic_get_properties(gatt_handle, &property_bits);
-        if (BT_ERROR_NONE != err) {
-          LoggerE("Properties of characteristic couldn't be acquired");
-        }
-        result_obj.insert(std::make_pair(
-            kBroadcast, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_BROADCAST))));
-        result_obj.insert(std::make_pair(
-            kReadable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_READ))));
-        result_obj.insert(std::make_pair(
-            kWriteNoResponse,
-            picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE))));
-        result_obj.insert(std::make_pair(
-            kWritable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE))));
-        result_obj.insert(std::make_pair(
-            kNotify, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_NOTIFY))));
-        result_obj.insert(std::make_pair(
-            kIndication, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_INDICATE))));
-        result_obj.insert(std::make_pair(
-            kSignedWrite, picojson::value(IsProperty(
-                              property_bits, BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES))));
-        result_obj.insert(std::make_pair(
-            kExtendedProperties,
-            picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_EXTENDED_PROPERTIES))));
-
-        auto uuid = UUID::createFromGatt(gatt_handle);
-        if (uuid) {
-          result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()}));
-        } else {
-          LoggerW("bt_gatt_get_uuid error: %d (%s)", err, get_error_message(err));
-          result_obj.insert(std::make_pair(kUuid, picojson::value{}));
-        }
-
-        array->push_back(result);
-        return true;
-      },
-      static_cast<void*>(&user_data));
-  if (platform_result.IsError()) {
-    return platform_result;
-  }
-  if (BT_ERROR_NONE != ret) {
-    LoggerE("Failed (%d)", ret);
-    return util::GetBluetoothError(ret, "Failed while getting characteristic");
-  }
-
-  return PlatformResult(ErrorCode::NO_ERROR);
-}
-
-void BluetoothGATTService::ReadValue(const picojson::value& args, picojson::object& out) {
-  ScopeLogger();
-  CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
-                                              &out);
-
-  const std::string& address = args.get("address").get<std::string>();
-  if (!IsStillConnected(address)) {
-    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
-                      ("Device with address %s is no longer connected", address.c_str()));
-    return;
-  }
-
-  const double callback_handle = util::GetAsyncCallbackHandle(args);
-  struct Data {
-    double callback_handle;
-    BluetoothGATTService* service;
-  };
-
-  Data* user_data = new Data{callback_handle, this};
-  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
-
-  auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
-    ScopeLogger("Entered into asynchronous function, read_value");
-    Data* data = static_cast<Data*>(user_data);
-    double callback_handle = data->callback_handle;
-    BluetoothGATTService* service = data->service;
-    delete data;
-
-    PlatformResult plarform_res = PlatformResult(ErrorCode::NO_ERROR);
-
-    picojson::value byte_array = picojson::value(picojson::array());
-    picojson::array& byte_array_obj = byte_array.get<picojson::array>();
-
-    if (BT_ERROR_NONE != result) {
-      plarform_res = util::GetBluetoothError(result, "Error while reading value");
-    } else {
-      char* value = nullptr;
-      int length = 0;
-      int ret = bt_gatt_get_value(handle, &value, &length);
-      if (BT_ERROR_NONE != ret) {
-        plarform_res = util::GetBluetoothError(ret, "Error while getting value");
-      } else {
-        for (int i = 0; i < length; i++) {
-          byte_array_obj.push_back(picojson::value(std::to_string(value[i])));
-        }
-      }
-      if (value) {
-        free(value);
-        value = nullptr;
-      }
-    }
-
-    std::shared_ptr<picojson::value> response =
-        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
-    if (plarform_res.IsSuccess()) {
-      ReportSuccess(byte_array, response->get<picojson::object>());
-    } else {
-      LogAndReportError(plarform_res, &response->get<picojson::object>());
-    }
-    TaskQueue::GetInstance().Async<picojson::value>(
-        [service, callback_handle](const std::shared_ptr<picojson::value>& response) {
-          service->instance_.SyncResponse(callback_handle, response);
-        },
-        response);
-  };
-  int ret = bt_gatt_client_read_value(handle, read_value, (void*)user_data);
-  if (BT_ERROR_NONE != ret) {
-    delete user_data;
-    user_data = nullptr;
-    LoggerE("Couldn't register callback for read value %d (%s)", ret, get_error_message(ret));
-  }
-  ReportSuccess(out);
-}
-
-void BluetoothGATTService::WriteValue(const picojson::value& args, picojson::object& out) {
-  ScopeLogger();
-  CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin,
-                                              &out);
-
-  const std::string& address = args.get("address").get<std::string>();
-  if (!IsStillConnected(address)) {
-    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
-                      ("Device with address %s is no longer connected", address.c_str()));
-    return;
-  }
-
-  const double callback_handle = util::GetAsyncCallbackHandle(args);
-  const picojson::array& value_array = args.get("value").get<picojson::array>();
-
-  int value_size = value_array.size();
-  std::unique_ptr<char[]> value_data(new char[value_size]);
-  for (int i = 0; i < value_size; ++i) {
-    value_data[i] = (int)value_array[i].get<double>();
-  }
-
-  struct Data {
-    double callback_handle;
-    BluetoothGATTService* service;
-  };
-
-  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
-
-  auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
-    ScopeLogger("Entered into asynchronous function, write_value");
-    Data* data = static_cast<Data*>(user_data);
-    double callback_handle = data->callback_handle;
-    BluetoothGATTService* service = data->service;
-    delete data;
-
-    PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR);
-    if (BT_ERROR_NONE != result) {
-      ret = util::GetBluetoothError(result, "Error while getting value");
-    }
-
-    std::shared_ptr<picojson::value> response =
-        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
-    if (ret.IsSuccess()) {
-      ReportSuccess(response->get<picojson::object>());
-    } else {
-      LogAndReportError(ret, &response->get<picojson::object>());
-    }
-    TaskQueue::GetInstance().Async<picojson::value>(
-        [service, callback_handle](const std::shared_ptr<picojson::value>& response) {
-          service->instance_.SyncResponse(callback_handle, response);
-        },
-        response);
-  };
-
-  int ret = bt_gatt_set_value(handle, value_data.get(), value_size);
-
-  if (BT_ERROR_NONE != ret) {
-    std::shared_ptr<picojson::value> response =
-        std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
-    LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"),
-                      &response->get<picojson::object>(),
-                      ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret)));
-    TaskQueue::GetInstance().Async<picojson::value>(
-        [this, callback_handle](const std::shared_ptr<picojson::value>& response) {
-          instance_.SyncResponse(callback_handle, response);
-        },
-        response);
-  } else {
-    Data* user_data = new Data{callback_handle, this};
-    ret = bt_gatt_client_write_value(handle, write_value, user_data);
-    if (BT_ERROR_NONE != ret) {
-      delete user_data;
-      LoggerE("Couldn't register callback for write value %d (%s)", ret, get_error_message(ret));
-    }
-  }
-  ReportSuccess(out);
-}
-
-void BluetoothGATTService::AddValueChangeListener(const picojson::value& args,
-                                                  picojson::object& out) {
-  ScopeLogger();
-  const auto& address = args.get("address").get<std::string>();
-  if (!IsStillConnected(address)) {
-    LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out,
-                      ("Device with address %s is no longer connected", address.c_str()));
-    return;
-  }
-
-  bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get(kHandle).get<double>());
-
-  int ret = bt_gatt_client_set_characteristic_value_changed_cb(handle, OnCharacteristicValueChanged,
-                                                               this);
-  if (BT_ERROR_NONE != ret) {
-    LogAndReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out,
-                      ("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d (%s)",
-                       ret, get_error_message(ret)));
-  } else {
-    gatt_characteristic_.push_back(handle);
-    ReportSuccess(out);
-  }
-}
-
-void BluetoothGATTService::RemoveValueChangeListener(const picojson::value& args,
-                                                     picojson::object& out) {
-  ScopeLogger();
-  const auto& address = args.get("address").get<std::string>();
-  if (!IsStillConnected(address)) {
-    LoggerW("Device with address %s is no longer connected", address.c_str());
-  } else {
-    bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get(kHandle).get<double>());
-
-    int ret = bt_gatt_client_unset_characteristic_value_changed_cb(handle);
-
-    if (BT_ERROR_NONE != ret) {
-      LoggerW("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d (%s)", ret,
-              get_error_message(ret));
-    } else {
-      gatt_characteristic_.erase(
-          std::remove(gatt_characteristic_.begin(), gatt_characteristic_.end(), handle),
-          gatt_characteristic_.end());
-    }
-  }
-  ReportSuccess(out);
-}
-
-common::PlatformResult BluetoothGATTService::GetServiceAllUuids(const std::string& address,
-                                                                picojson::array* array) {
-  ScopeLogger();
-
-  bt_gatt_client_h client = GetGattClient(address);
-
-  if (nullptr == client) {
-    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to create client");
-  }
-
-  auto foreach_callback = [](int total, int index, bt_gatt_h gatt_handle, void* user_data) -> bool {
-    ScopeLogger("Entered into asynchronous function, foreach_callback, total: %d, index: %d", total,
-                index);
-
-    auto& uuids = *static_cast<picojson::array*>(user_data);
-    auto uuid = UUID::createFromGatt(gatt_handle);
-    if (uuid) {
-      /*
-       * BACKWARD COMPATIBILITY
-       *
-       * In the past, this function has always trimmed UUIDs retrieved
-       * from native API to 16 bit format. UUIDs that were not created
-       * from 16 bit UUID and BASE_UUID were converted to invalid values.
-       *
-       * We return UUIDs in shortest possible format to comply with past
-       * behaviour when possible. If the UUID is not convertible
-       * to 16 bit UUID, we return a longer form.
-       */
-      uuids.push_back(picojson::value{uuid->ShortestPossibleFormat()});
-    } else {
-      LoggerE("Couldn't get UUID from bt_gatt_h");
-    }
-
-    return true;
-  };
-
-  int ret = bt_gatt_client_foreach_services(client, foreach_callback, array);
-
-  if (BT_ERROR_NONE == ret) {
-    return PlatformResult(ErrorCode::NO_ERROR);
-  } else {
-    return util::GetBluetoothError(ret, "Failed to get UUIDS");
-  }
-}
-
-void BluetoothGATTService::OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value,
-                                                        int length, void* user_data) {
-  ScopeLogger("characteristic: [%p], len: [%d], user_data: [%p]", characteristic, length,
-              user_data);
-
-  auto service = static_cast<BluetoothGATTService*>(user_data);
-
-  if (!service) {
-    LoggerE("user_data is NULL");
-    return;
-  }
-
-  picojson::value result = picojson::value(picojson::object());
-  picojson::object& result_obj = result.get<picojson::object>();
-
-  result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)characteristic)));
-
-  picojson::value byte_array = picojson::value(picojson::array());
-  picojson::array& byte_array_obj = byte_array.get<picojson::array>();
-
-  for (int i = 0; i < length; ++i) {
-    byte_array_obj.push_back(picojson::value(std::to_string(value[i])));
-  }
-
-  ReportSuccess(byte_array, result_obj);
-
-  service->instance_.FireEvent(kOnValueChanged, result);
-}
-
-}  // namespace bluetooth
-}  // namespace extension
diff --git a/src/bluetooth/bluetooth_gatt_service.h b/src/bluetooth/bluetooth_gatt_service.h
deleted file mode 100644 (file)
index d4e5446..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *    Licensed 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.
- */
-
-#ifndef BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_
-#define BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_
-
-#include <map>
-
-#include <bluetooth.h>
-
-#include "bluetooth/uuid.h"
-#include "common/picojson.h"
-#include "common/platform_result.h"
-
-namespace extension {
-namespace bluetooth {
-
-class BluetoothInstance;
-
-class BluetoothGATTService {
- public:
-  BluetoothGATTService(BluetoothInstance& instance);
-  ~BluetoothGATTService();
-
-  common::PlatformResult GetSpecifiedGATTService(const std::string& address, const UUID& uuid,
-                                                 picojson::object* result);
-
-  void TryDestroyClient(const std::string& address);
-  void GetServices(const picojson::value& data, picojson::object& out);
-  void GetCharacteristics(const picojson::value& data, picojson::object& out);
-  void ReadValue(const picojson::value& args, picojson::object& out);
-  void WriteValue(const picojson::value& args, picojson::object& out);
-  void AddValueChangeListener(const picojson::value& args, picojson::object& out);
-  void RemoveValueChangeListener(const picojson::value& args, picojson::object& out);
-
-  common::PlatformResult GetServiceAllUuids(const std::string& address, picojson::array* array);
-
- private:
-  bool IsStillConnected(const std::string& address);
-
-  bt_gatt_client_h GetGattClient(const std::string& address);
-
-  common::PlatformResult GetServicesHelper(bt_gatt_h handle, const std::string& address,
-                                           picojson::array* array);
-  common::PlatformResult GetCharacteristicsHelper(bt_gatt_h handle, const std::string& address,
-                                                  picojson::array* array);
-
-  static void OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, int len,
-                                           void* user_data);
-
-  std::map<std::string, bt_gatt_client_h> gatt_clients_;
-  std::vector<bt_gatt_h> gatt_characteristic_;
-
-  BluetoothInstance& instance_;
-};
-
-}  // namespace bluetooth
-}  // namespace extension
-
-#endif  // BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_
index 2ff079ea9f322b7e194f96883988632e565b8b53..91fb4885dbdba346b48d8adef611d3a312577d46 100644 (file)
@@ -35,8 +35,8 @@ BluetoothInstance::BluetoothInstance()
       bluetooth_service_handler_(bluetooth_adapter_),
       bluetooth_socket_(bluetooth_adapter_),
       bluetooth_le_adapter_(*this),
-      bluetooth_gatt_service_(*this),
-      bluetooth_le_device_(*this, bluetooth_gatt_service_),
+      bluetooth_gatt_client_service_(*this),
+      bluetooth_le_device_(*this, bluetooth_gatt_client_service_),
       worker(),
       bluetooth_gatt_server_(*this) {
   ScopeLogger();
@@ -93,12 +93,12 @@ BluetoothInstance::BluetoothInstance()
   REGISTER_METHOD(BluetoothLEDeviceRemoveConnectStateChangeListener);
   REGISTER_METHOD(BluetoothLEDeviceGetServiceAllUuids);
 
-  REGISTER_METHOD(BluetoothGATTServiceGetServices);
-  REGISTER_METHOD(BluetoothGATTServiceGetCharacteristics);
-  REGISTER_METHOD(BluetoothGATTServiceReadValue);
-  REGISTER_METHOD(BluetoothGATTServiceWriteValue);
-  REGISTER_METHOD(BluetoothGATTServiceAddValueChangeListener);
-  REGISTER_METHOD(BluetoothGATTServiceRemoveValueChangeListener);
+  REGISTER_METHOD(BluetoothGATTClientServiceGetServices);
+  REGISTER_METHOD(BluetoothGATTClientServiceGetCharacteristics);
+  REGISTER_METHOD(BluetoothGATTClientServiceReadValue);
+  REGISTER_METHOD(BluetoothGATTClientServiceWriteValue);
+  REGISTER_METHOD(BluetoothGATTClientServiceAddValueChangeListener);
+  REGISTER_METHOD(BluetoothGATTClientServiceRemoveValueChangeListener);
 
   REGISTER_METHOD(BluetoothGATTServerStart);
   REGISTER_METHOD(BluetoothGATTServerStop);
@@ -406,40 +406,40 @@ void BluetoothInstance::BluetoothLEDeviceGetServiceAllUuids(const picojson::valu
   bluetooth_le_device_.GetServiceAllUuids(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceGetServices(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceGetServices(const picojson::value& args,
                                                         picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.GetServices(args, out);
+  bluetooth_gatt_client_service_.GetServices(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceGetCharacteristics(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceGetCharacteristics(const picojson::value& args,
                                                                picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.GetCharacteristics(args, out);
+  bluetooth_gatt_client_service_.GetCharacteristics(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceReadValue(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceReadValue(const picojson::value& args,
                                                       picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.ReadValue(args, out);
+  bluetooth_gatt_client_service_.ReadValue(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceWriteValue(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceWriteValue(const picojson::value& args,
                                                        picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.WriteValue(args, out);
+  bluetooth_gatt_client_service_.WriteValue(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceAddValueChangeListener(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceAddValueChangeListener(const picojson::value& args,
                                                                    picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.AddValueChangeListener(args, out);
+  bluetooth_gatt_client_service_.AddValueChangeListener(args, out);
 }
 
-void BluetoothInstance::BluetoothGATTServiceRemoveValueChangeListener(const picojson::value& args,
+void BluetoothInstance::BluetoothGATTClientServiceRemoveValueChangeListener(const picojson::value& args,
                                                                       picojson::object& out) {
   ScopeLogger();
-  bluetooth_gatt_service_.RemoveValueChangeListener(args, out);
+  bluetooth_gatt_client_service_.RemoveValueChangeListener(args, out);
 }
 
 void BluetoothInstance::BluetoothGATTServerStart(const picojson::value& args,
index 0ee235dfad65934b532d37785acf8701afbf2673..48ac8d0a2e29ffb849259990539310615260f51c 100644 (file)
@@ -22,7 +22,7 @@
 #include "bluetooth/bluetooth_adapter.h"
 #include "bluetooth/bluetooth_device.h"
 #include "bluetooth/bluetooth_gatt_server.h"
-#include "bluetooth/bluetooth_gatt_service.h"
+#include "bluetooth/bluetooth_gatt_client_service.h"
 #include "bluetooth/bluetooth_health_application.h"
 #include "bluetooth/bluetooth_health_channel.h"
 #include "bluetooth/bluetooth_health_profile_handler.h"
@@ -100,13 +100,13 @@ class BluetoothInstance : public common::ParsedInstance {
                                                          picojson::object& out);
   void BluetoothLEDeviceGetServiceAllUuids(const picojson::value& args, picojson::object& out);
 
-  void BluetoothGATTServiceGetServices(const picojson::value& args, picojson::object& out);
-  void BluetoothGATTServiceGetCharacteristics(const picojson::value& args, picojson::object& out);
-  void BluetoothGATTServiceReadValue(const picojson::value& args, picojson::object& out);
-  void BluetoothGATTServiceWriteValue(const picojson::value& args, picojson::object& out);
-  void BluetoothGATTServiceAddValueChangeListener(const picojson::value& args,
+  void BluetoothGATTClientServiceGetServices(const picojson::value& args, picojson::object& out);
+  void BluetoothGATTClientServiceGetCharacteristics(const picojson::value& args, picojson::object& out);
+  void BluetoothGATTClientServiceReadValue(const picojson::value& args, picojson::object& out);
+  void BluetoothGATTClientServiceWriteValue(const picojson::value& args, picojson::object& out);
+  void BluetoothGATTClientServiceAddValueChangeListener(const picojson::value& args,
                                                   picojson::object& out);
-  void BluetoothGATTServiceRemoveValueChangeListener(const picojson::value& args,
+  void BluetoothGATTClientServiceRemoveValueChangeListener(const picojson::value& args,
                                                      picojson::object& out);
   void BluetoothGATTServerStart(const picojson::value& args, picojson::object& out);
   void BluetoothGATTServerStop(const picojson::value& args, picojson::object& out);
@@ -119,7 +119,7 @@ class BluetoothInstance : public common::ParsedInstance {
   BluetoothServiceHandler bluetooth_service_handler_;
   BluetoothSocket bluetooth_socket_;
   BluetoothLEAdapter bluetooth_le_adapter_;
-  BluetoothGATTService bluetooth_gatt_service_;
+  BluetoothGATTClientService bluetooth_gatt_client_service_;
   BluetoothLEDevice bluetooth_le_device_;
   common::Worker worker;
   // If all operations on bluetooth_gatt_server_ will be done by the worker,
index 413a30592c1fd0a808b4b4687eb52ec1144bbaac..bbcf715feaa95c08ab6652093a9d37af23720249 100644 (file)
@@ -55,7 +55,7 @@ const std::string kOnDisconnected = "ondisconnected";
 const std::string kConnectChangeEvent = "BluetoothLEConnectChangeCallback";
 }
 
-BluetoothLEDevice::BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTService& service)
+BluetoothLEDevice::BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTClientService& service)
     : instance_(instance), service_(service), is_listener_set_(false) {
   ScopeLogger();
   int ret = bt_gatt_set_connection_state_changed_cb(GattConnectionState, this);
@@ -393,7 +393,7 @@ void BluetoothLEDevice::GetService(const picojson::value& data, picojson::object
   picojson::value response = picojson::value(picojson::object());
   picojson::object* data_obj = &response.get<picojson::object>();
 
-  PlatformResult result = service_.GetSpecifiedGATTService(address, *uuid, data_obj);
+  PlatformResult result = service_.GetSpecifiedGATTClient(address, *uuid, data_obj);
 
   if (result.IsError()) {
     LogAndReportError(result, &out);
index 25d0f5fc34a188576949cb3e242f453cbb691b48..99f42aae179d66fbb6e55627d3f8fc307a333d12 100644 (file)
@@ -22,7 +22,7 @@
 #include <set>
 #include <unordered_map>
 
-#include "bluetooth/bluetooth_gatt_service.h"
+#include "bluetooth/bluetooth_gatt_client_service.h"
 
 #include "bluetooth/uuid.h"
 #include "common/picojson.h"
@@ -35,7 +35,7 @@ class BluetoothInstance;
 
 class BluetoothLEDevice {
  public:
-  explicit BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTService& service);
+  explicit BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTClientService& service);
   ~BluetoothLEDevice();
 
   void Connect(const picojson::value& data, picojson::object& out);
@@ -60,7 +60,7 @@ class BluetoothLEDevice {
   void CleanClientInfo(const char* remote_address);
   void TriggerConnectStateChangeListener(const char* remote_address, bool connected);
   BluetoothInstance& instance_;
-  BluetoothGATTService& service_;
+  BluetoothGATTClientService& service_;
   std::unordered_map<std::string, double> connecting_;
   bool is_listener_set_;
   std::set<std::string> is_connected_;
index ac08c153899f0a119b6ad6168bb7c1ca5d2fae12..35f30d9b2b7eaa5bd5c8ef7941072f94ba274fa1 100644 (file)
@@ -90,7 +90,7 @@ struct UUID {
    * work in the following manner:
    * 1. the user passes them a UUID, in any acceptable format, e.g.: "aBcD"
    * 2. the function performs requested operations using the passed UUID
-   * 3. the function creates an object, e.g. BlueoothGATTService, with the UUID
+   * 3. the function creates an object, e.g. BluetoothGATTClientService, with the UUID
    *    passed by the user.
    *
    * As user may expect an identical UUID in the created object, identical to