SAP HANA Cloud Platform: загрузка и хранение данных

от автора

В предыдущей статье мы рассказали о том, как создать тестовый экземпляр облачной платформы (далее HCP — HANA Cloud Platform) и как связать среду разработки Eclipse с облаком на примере простейшего XS приложения (XS — eXtended Services).

Сейчас мы хотели бы пойти дальше и показать, как можно загружать данные в базу данных из внешнего сервиса. При этом будут показаны некоторые тонкости при работе с trial облаком, связанные с требованиями изоляции пользователей в рамках одной trial системы.

Итак, что мы имеем. Первое — доступ к панели управления нашего облака по адресу https://account.hanatrial.ondemand.com/cockpit

Второе — созданный экземпляр платформы на SAP HANA под названием helloworldtrial.
image
Третье — установленную среду разработки Eclipse с плагином для SAP HANA Cloud и с созданным подключением к helloworldtrial:
image
Что мы хотим сделать: создать таблицу в базе данных SAP HANA и загрузить туда данные из внешнего источника. Для наших целей будем хранить информацию о текущей температуре воздуха в нескольких городах. Данные, для примера, будем брать с openweathermap.org.

Начнём с создания нового проекта. Запускаем наш Eclipse, открываем перспективу SAP HANA Development (Window > Open Perspective > Other…):
image
Создаём новый проект XS приложения, указав его название (File > New > Project… > SAP HANA Cloud):
image
Далее нам требуется выполнить стандартные шаги по выбору workspace’а и пакета. Внимание! Для нашего примера важно выбрать пакет, соответствующий нашему экземпляру облачной системы, вида pXXXXXXXXtrial.helloworldtrial. Где pXXXXXXXXtrial — имя пользователя в облачной системе:
image
И укажем наш главный файл со скриптом, который и будет выполнять всю работу — get_weather.xsjs:
image

Контроль доступа к пакету. Файл .xsaccess
С помощью файла .xsaccess мы указываем свойства нашего XS приложения (например, требуемая авторизация для исполнения скрипта и т.д.). Заменим содержимое этого файла на:

{      "exposed" : true,      "default_file" : "get_weather.xsjs" } 

Свойство exposed показывает, что данное XS приложение может быть выполнено на сервере из URL. Свойство default_file указывает главный исполняемый файл приложения; это позволит нам запустить его напрямую из панели управления (cockpit), не дописывая имя файла.

Теперь активируем наше приложение для проверки того, что на данном этапе все шаги были выполнены правильно. Для этого щёлкнем правой кнопкой мыши на нашем проекте во вкладке Project Explorer и в контекстном меню выберем Team > Activate.

Перезапустим панель управления в веб браузере нажав обновить (F5); иначе наше XS приложение не отображается в списке:
image
Щёлкнем на URL нашего XS приложения:
image
Должно открыться новое окно с содержимым “Wrong content type request use application/json”. Удостоверившись, что наша заготовка запускается, мы можем двигаться дальше.

Создание таблицы в базе данных
Создадим таблицу в базе данных, которая будет содержать столбцы: дата и время, наименование населённого пункта и текущую температуру воздуха.
Есть несколько способов создать таблицу в системе — с помощью интерактивного дизайнера, SQL скрипта или .hdbtable файла.

Самый быстрый способ — запустить на выполнение скрипт, подставив имя нашей схемы. Идём на вкладку Systems и запускаем SQL консоль для нашего облака:
image
Запускаем такой скрипт, подставив имя нашей схемы 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_, увидим нашу таблицу:
image

Роль пользователя БД. Файл .hdbrole
В бесплатной trial системе у пользователя есть весьма ограниченный набор прав. Это касается, в частности, авторизации на изменение объектов в каталоге и управления пользовательскими аккаунтами. Поэтому в trial системе есть набор процедур в схеме “HCP”, которые позволяют пользователю управлять правами на созданные им объекты.

Для записи и чтения данных таблицы T_WEATHER нам потребуется новая роль. Добавим файл типа .hdbrole в наш проект (в главном меню File > New > Other…):
image
назовём его weather_access:
image
Заменим содержимое этого файла на следующий фрагмент, а затем активируем файл:

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_:
image

var CONST_ROOT_PACKAGE = "<<<pXXXXXtrial>>>"; var CONST_NEO_SCHEMA = "<<<NEO_XXXXXXXXXXXXXXXX>>>";  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 <<table>> (FORECAST_TMSTMP,LOCATION,TEMPERATURE) VALUES (?,?,?)"); 

Доступ к внешнему URL. Файл .xshttpdest
Добавим новый объект типа .xshttpdest с названием o_weather в наш проект:
image
И заменим содержимое этого файла на:

host = "api.openweathermap.org"; port = 80; description = "current weather"; useSSL = false; pathPrefix = "/data/2.5/weather"; authType = none; useProxy = true; proxyHost = "proxy-trial"; proxyPort = 8080; timeout = 5000; // in milliseconds 

Сохраним и активируем этот объект.

Теперь в панели управления HCP на вкладке с XS приложениями мы увидим новый элемент в панели Destinations:
image
Кликнув на URL нашего приложения, запустим скрипт и получим приблизительно такой результат на экране:
image
Теперь в Eclipse проверим, что данные были сохранены в таблице. Для этого по правой кнопке мыши на таблице T_WEATHER выберем Open Data Preview:
image
И убедимся, что новая запись в базе данных была создана:
image

Итого
Итак, в данной статье мы создали XS приложение, которое умеет получать данные из внешнего источника (в нашем случае — веб сервис) и сохранять их в таблице в базе данных HANA. Кроме того, мы создали два специальных объекта: определение ролей (weather_access.hdbrole) и определение канала для доступа к внешнему веб-сервису (o_weather.xshttpdest). А также вызвали хранимые процедуры для того, чтобы в trial системе дать разрешения на доступ к таблице базы данных.

ссылка на оригинал статьи http://habrahabr.ru/post/257761/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *