SAP HANA Cloud Platform: загрузка и хранение данных
В предыдущей статье мы рассказали о том, как создать тестовый экземпляр облачной платформы (далее HCP — HANA Cloud Platform) и как связать среду разработки Eclipse с облаком на примере простейшего XS приложения (XS — eXtended Services).Сейчас мы хотели бы пойти дальше и показать, как можно загружать данные в базу данных из внешнего сервиса. При этом будут показаны некоторые тонкости при работе с trial облаком, связанные с требованиями изоляции пользователей в рамках одной trial системы.
Итак, что мы имеем. Первое — доступ к панели управления нашего облака по адресу https://account.hanatrial.ondemand.com/cockpit
Второе — созданный экземпляр платформы на SAP HANA под названием helloworldtrial.Третье — установленную среду разработки Eclipse с плагином для SAP HANA Cloud и с созданным подключением к helloworldtrial: Что мы хотим сделать: создать таблицу в базе данных SAP HANA и загрузить туда данные из внешнего источника. Для наших целей будем хранить информацию о текущей температуре воздуха в нескольких городах. Данные, для примера, будем брать с openweathermap.org.
Начнём с создания нового проекта. Запускаем наш Eclipse, открываем перспективу SAP HANA Development (Window > Open Perspective > Other…): Создаём новый проект XS приложения, указав его название (File > New > Project… > SAP HANA Cloud): Далее нам требуется выполнить стандартные шаги по выбору workspace«а и пакета. Внимание! Для нашего примера важно выбрать пакет, соответствующий нашему экземпляру облачной системы, вида pXXXXXXXXtrial.helloworldtrial. Где pXXXXXXXXtrial — имя пользователя в облачной системе: И укажем наш главный файл со скриптом, который и будет выполнять всю работу — get_weather.xsjs:
Контроль доступа к пакету. Файл .xsaccessС помощью файла .xsaccess мы указываем свойства нашего XS приложения (например, требуемая авторизация для исполнения скрипта и т.д.). Заменим содержимое этого файла на:
{ «exposed» : true, «default_file» : «get_weather.xsjs» } Свойство exposed показывает, что данное XS приложение может быть выполнено на сервере из URL. Свойство default_file указывает главный исполняемый файл приложения; это позволит нам запустить его напрямую из панели управления (cockpit), не дописывая имя файла.Теперь активируем наше приложение для проверки того, что на данном этапе все шаги были выполнены правильно. Для этого щёлкнем правой кнопкой мыши на нашем проекте во вкладке Project Explorer и в контекстном меню выберем Team > Activate.
Перезапустим панель управления в веб браузере нажав обновить (F5); иначе наше XS приложение не отображается в списке: Щёлкнем на URL нашего XS приложения: Должно открыться новое окно с содержимым «Wrong content type request use application/json». Удостоверившись, что наша заготовка запускается, мы можем двигаться дальше.
Создание таблицы в базе данныхСоздадим таблицу в базе данных, которая будет содержать столбцы: дата и время, наименование населённого пункта и текущую температуру воздуха.Есть несколько способов создать таблицу в системе — с помощью интерактивного дизайнера, SQL скрипта или .hdbtable файла.
Самый быстрый способ — запустить на выполнение скрипт, подставив имя нашей схемы. Идём на вкладку Systems и запускаем SQL консоль для нашего облака: Запускаем такой скрипт, подставив имя нашей схемы NEO_:
create column table «NEO_<<<>>>».«T_WEATHER»( «ID» INTEGER GENERATED ALWAYS AS IDENTITY (MINVALUE 0 START WITH 0 INCREMENT BY 1), «FORECAST_TMSTMP» TIMESTAMP NOT NULL, «LOCATION» NVARCHAR (50) NOT NULL, «TEMPERATURE» REAL NOT NULL, «TIMESTMP» TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY («ID»)); Обратим внимание на то, что мы создаём таблицу с колоночным хранением. А также неявно создаём т.н. sequence, который генерирует последовательность целых чисел и, при создании записей в таблице, сохраняет их в атрибуте ID.Обновив каталог NEO_, увидим нашу таблицу:
Роль пользователя БД. Файл .hdbroleВ бесплатной trial системе у пользователя есть весьма ограниченный набор прав. Это касается, в частности, авторизации на изменение объектов в каталоге и управления пользовательскими аккаунтами. Поэтому в trial системе есть набор процедур в схеме «HCP», которые позволяют пользователю управлять правами на созданные им объекты.
Для записи и чтения данных таблицы T_WEATHER нам потребуется новая роль. Добавим файл типа .hdbrole в наш проект (в главном меню File > New > Other…): назовём его weather_access: Заменим содержимое этого файла на следующий фрагмент, а затем активируем файл:
role p<<<>>>trial.helloworldtrial.TryWeather: weather_access { catalog sql object «NEO_<<<>>>>».«T_WEATHER»: SELECT, UPDATE, INSERT; } Заменим p>>trial на имя вашего пользователя. Вместо схемы NEO_>>> необходимо вставить наименование своей схемы, которую мы сохранили при создании таблицы. А теперь начинается магия, связанная с тем, что наше облако в триал режиме создаёт множество пользователей на одной системе. И для разделения прав доступа у этих пользователей весьма ограниченные привилегии.Для того, чтобы наш системный пользователь получил роль weather_access мы должны выполнить системную процедуру.Запустим SQL консоль и в ней выполним такой скрипт:
call «HCP».«HCP_GRANT_ROLE_TO_USER»('p<<<>>>trial .helloworldtrial.TryWeather: weather_access', 'p<<<>>>');
Дополнительные встроенные процедуры в trial системе
Хотелось бы обратить внимание на то, что при изменении таблиц, представлений, процедур в каталоге trial системы необходимо в явном виде обновлять разрешения на доступ к этим объектам. Это делается вызовом процедуры:
call «HCP».«HCP_GRANT_SELECT_ON_ACTIVATED_OBJECTS»;
После изменения и активации файла .hdbrole необходимо выполнить:
call «HCP».«HCP_GRANT_ACTIVATED_ROLES»;
Основной скрипт. Файл .xsjsИтак, у нас есть заготовка XS скрипта и таблица в базе данных, для которой мы добавили разрешение на запись и чтение данных. В эту таблицу мы будем записывать данные о текущей погоде.Откуда можно получать данные о погоде
Для получения температуры мы используем API от openweathermap.org. Подробнее данный сервис был описан в статье на Хабре.Пример URL для получения текущих данных о погоде в Москве: http://api.openweathermap.org/data/2.5/weather? q=Moscow, ru&units=metric.Полученные данные в виде JSON объекта содержат, в том числе, информацию о температуре воздуха в формате unix timestamp. Тэг «dt»:
{
…
«dt » : 1430318471,
«id » : 524901,
«name » : «Moscow »,
«cod » : 200
}
Мы извлечём данные о погоде и запишем их в таблицу.Исходный код скрипта
Важно! Замените значения констант в первых двух строках на ваш логин (заканчивается на -trial) и наименование схемы базы данных NEO_:
var CONST_ROOT_PACKAGE = »<<
function getCurrentWeather (city_name) { var destination_package = «helloworldtrial.TryWeather»; var destination_name = «o_weather»;
var destPackagePath = CONST_ROOT_PACKAGE + ».» + destination_package; var dest = $.net.http.readDestination (destPackagePath, destination_name);
var client = new $.net.http.Client (); var req = new $.web.WebRequest ($.net.http.GET,»? q=» + city_name + »&units=metric»); client.request (req, dest); var response = client.getResponse ();
var weather_data = JSON.parse (response.body.asString (), function (key, value) { if (key === «dt») { return new Date (value * 1000); } return value; }); return [ weather_data.dt, city_name, weather_data.main.temp ]; }
function storeData (data_receiving_time, city, temp) {
var conn = $.db.getConnection (); var stmt = conn .prepareStatement («INSERT INTO \» + CONST_NEO_SCHEMA + »\».T_WEATHER (FORECAST_TMSTMP, LOCATION, TEMPERATURE) VALUES (?,?,?)»);
stmt.setTimestamp (1, data_receiving_time);// время получения данных о погоде OpenWeatherMap stmt.setString (2, city); stmt.setFloat (3, temp);
var rs = stmt.executeQuery ();
rs.close (); stmt.close (); conn.commit (); conn.close ();
}
function processRequest () { var cityNames = [ «Moscow, ru», «Saint Petersburg, ru», «Novosibirsk, ru», «Volgograd, ru», «Krasnoyarsk, ru» ]; var body = »; var cityName, i; var dt; var city; var temp; var out_vals;
try { for (i = 0; i < cityNames.length; i++) { cityName = cityNames[i]; out_vals = getCurrentWeather(cityName); dt = out_vals[0]; city = out_vals[1]; temp = out_vals[2];
storeData (dt, city, temp); body += «Данные сохранены.\nДата:» + dt + »\nГород:» + city + »\nТемпература:» + temp + » C\n\n»;
} $.response.setBody (body); $.response.contentType = «text/plain»; $.response.status = $.net.http.OK;
} catch (e) { $.response.contentType = «text/plain»; $.response.status = $.net.http.INTERNAL_SERVER_ERROR; $.response.setBody (e.toString ()); } }
processRequest (); Данный код использует т.н. destination для вызова внешнего API.А доступ к базе данных из Javascript осуществляется через объект соединения в пространстве имён $.db: var conn = $.db.getConnection (); var stmt = conn.prepareStatement («INSERT INTO <