December 30th, 2014

Разработка веб-приложений на Scala: среда разработки

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

Лично я - стандартный программист на Яве, в своё время для веб-разработки приноровился к JSP+Tomcat, с тех пор для для небольших эпизодических задач мне их вполне хватало. Но т.к. Сервер Роботов не просто крутится где-то в облаке, но и публикуется с исходным кодом в виде уроков, я не хотел использовать для него совсем уж откровенное (хотя и вполне актуальное) старьё, поэтому решил попробовать что-нибудь современное ультра-модное, но чтобы не совсем маргинальное. В этом смысле я уже давно посматривал в сторону функционального программирования вообще и Скалы в частности, теперь появился повод попробовать ее на практике конкретно в области веб-разработки.

А вообще в области программирования для веба существует большое количество разнообразных платформ, языков и фреймворков; по быстрому и углубленному знакомству с ними написано и напечатано большое количество разнообразных статей, постов и книг. Поэтому на основах Скалы и веб-разработки подробно останавливаться не буду; основной интерес для меня в конечном итоге будут представлять подключенные к серверу роботы, а на чем написан вспомогательный веб-интерфейс - вопрос второстепенный, при желании Скалу можно всегда можно заменить на любимый Раби или ПоХаПэ.

Почему Скала

очевидно из трейлера:



Скалу часто представляют как улучшенную Яву и говорят о том, что на неё довольно просто будет перейти Ява-программистам. Действительно, программы, написанные на Скале, компилируются в классы, которые работают поверх обычной глобальной и надёжной Ява-машины. В программе на Скале можно использовать любые библиотеки, написанные для обычной Явы (пожалуй, это важнейшее преимущество). Скала также является объектно-ориентированным языком, хотя точнее она одновременно включает объектно-ориентированные и функциональные парадигмы программирования.

Однако, для того, чтобы легко понимать программы, написанные на Скале (не говоря о том, чтобы писать), знания одной Явы может быть недостаточно. Множество новаций в Скале касаются именно синтаксиса. По моим первым впечатлениям, она старается быть настолько лаконичной, насколько это возможно. Программист может опускать разнообразные ключевые слова (например, не указывать тип данных при инициализации переменных, или даже не писать ключевое слово "return") - что именно имелось ввиду в каждом случае, будет пытаться понять из контекста компилятор. Явный плюс такого подхода - программы действительно получаются очень лаконичными, их (как я постепенно начал ощущать) довольно приятно писать, т.к. в коде можно набирать только то, что действительно важно. Побочный эффект такой лаконичности - при чтении чужого кода (примера из интернета или кода библиотеки) работу компилятора приходится осуществлять читающему человеку.

Лично у меня сходу не получилось вникнуть в смысл некоторых примеров кода на Скале, которые я рассматривал на старте, ни с первого, ни со второго раза, как это часто прокатывало с другими языками. Поэтому если вы начнете ощущать накатывающееся раздражение при просмотре некоторых фрагментов кода на Скале, которые будут приведены далее, из-за того, что вы непрерывно смотрите на эти три строчки уже восемнадцать минут и все равно не понимаете, что там, блин, написано, настоятельно рекомендую предварительно прочитать какую-нибудь вводную книгу по основам языка. Хороший вариант - «Функциональное программирование. SCALA для нетерпеливых.», Кей Хорстман (Cay Horstmann).


«Функциональное программирование. SCALA для нетерпеливых» Кей Хорстман

Или просто перепишите всё на своём любимом языке программирования.

Collapse )

Вторая часть: пишем веб-приложение на Scala+Unfiltered.

исходники занятия, подсветка синтаксиса.

Разработка веб-приложений на Scala: пишем приложение с Unfiltered

Среду разработки Netbeans для работы со Scala настроили, пишем и запускаем веб-приложение с фреймворком Unfiltered.

Collapse )

Третья часть о том, как развернуть веб-приложение в облаке.

исходники занятия, подсветка синтаксиса.

Разработка веб-приложений на Scala: развернуть приложение в облаке

Среду разработки Netbeans для работы со Scala настроили, веб-приложение с фреймворком Unfiltered написали и запустили, теперь развернём его в облаке, т.е. получим настоящий личный веб-сервис.

Развернуть веб-приложение в облаке

Для начала стоит обзавестить виртуальным хостингом, например в облаке Амазон (сейчас правда актуально поискать хорошие отечественные аналоги с ценником в рублях).

Дальше нужно загрузить исполняемый jar-файл scala-unfiltered-basic-demo-1.0-SNAPSHOT.jar и библиотеки с зависимостями - весь каталог lib (оба появятся в каталоге ScalaUnfilteredBasicDemo/target после сборки проекта с Maven в Netbeans) в удобное место на виртуальном сервере через sftp.

Дальше запускать как обычное java-приложение с исполняемым jar-файлом, как мы уже делали с Сервером Роботов.

Установим платформу Java, если не сделали этого ранее:

] sudo apt-get update
] sudo apt-get install default-jre


Проверим, что всё ОК:
] java -version
java version "1.7.0_51"
OpenJDK Runtime Environment (IcedTea 2.4.4) (7u51-2.4.4-0ubuntu0.13.10.1)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)

В каталоге с jar-файлом и каталогом lib. Проверим, что все на месте:
] ls
lib  scala-unfiltered-basic-demo-1.0-SNAPSHOT.jar

Запускаем:
] java -jar scala-unfiltered-basic-demo-1.0-SNAPSHOT.jar
Starting Scala Unfiltered web framework demo on Jetty http server...
2014-12-29 22:41:49.990:INFO:oejs.Server:jetty-8.1.13.v20130916
2014-12-29 22:41:50.093:INFO:oejs.AbstractConnector:Started SocketConnector@0.0.0.0:8080

Дальше, как и раньше, проверяем веб-приложение из браузера с локального компьютера, только вместо localhost используем ip-адрес виртуального сервера (например: http://54.200.48.84:8080/) или доменное имя, если оно назначено (http://robotc.lasto4ka.su:8080/).

Чтобы тест прошел успешно, очевидно, следует заранее открыть для публичного доступа порт 8080 в настройках безопасности виртуальной машины в Консоли управления веб-сервисами Амазон (AWS Management Console).

Демонизация Явы и фасад

В целом, знакомство с основами веб-разработки на Скале и Unfiltered на этом завершается, осталось только добавить два штриха для полноты картины.

Фоновые сервисы

Если запускать веб-приложение просто как java -jar в обычном приглашении ssh, оно будет работать ровно до тех пор, пока мы не закроем это приглашение. Для того, чтобы этого не происходило, запустим его как системный фоновый сервис (в термилогии Линукса - демон).

Для того, чтобы превратить любой процесс в фоновый сервис, в Линуксе есть специальная утилита setsid:

] setsid java -jar scala-unfiltered-basic-demo-1.0-SNAPSHOT.jar

Теперь можно закрывать все открытые сессии ssh и выключать компьютер, веб-приложение продолжит работать в облаке. Однако теперь появляются две проблемы: как теперь остановить запущенный сервис и как следить за его отладочными сообщениями. Для системы наш сервис является обычным процессом с именем java, поэтому самый простой способ его остановить - набрать "killall java" в любой старой или вновь открытой сессии ssh. Однако с таким подходом мы можем убить и все остальные процессы java, запущенные в системе.

Чтобы этого не происходило, нам нужно сохранить идентификатор нужного нам фонового процесса (pid - process id) в момент запуска. Для этого используем простой скрипт:

] nano scalaweb.sh

#!/bin/sh
setsid java -jar scala-unfiltered-basic-demo-1.0-SNAPSHOT.jar > scalaweb.log 2>&1 &
echo $!>scalaweb.pid


Разрешим скрипту выполняться:
] chmod +x scalaweb.sh

Запуск веб-приложения теперь выглядит так:
] ./scalaweb.sh

Теперь pid фонового сервиса java с нашим веб-приложением будет попадать в файл scalaweb.pid, останавливать вручную можно таким способом:

] cat scalaweb.pid
14265
] kill 14265

Все отладочные сообщения, кстати, уже тоже пишутся в файл scalaweb.log.

Конечно, это не лучшая версия скрипта для запуска фонового сервиса, обычно используются более функциональные версии, которые как минимум принимают параметры start/stop/restart для удобного управления сервисом. Но работать мой спартанский вариант будет не хуже, а как делать нормальные скрипты для демонизации процессов можно посмотреть в интернете самостоятельно.

Фасад для веб-приложения Java

Хотя мы видим, что наше веб-приложение уже отлично взаимодействует с веб-браузером, который обращается к нему через порт 8080 (номер порта можно заменить на произвольный), по ряду причин веб-приложения, работающие на виртуальной машине Java, не принято выставлять на всеобщее обозрение напрямую на 80й порт. Вместо этого для них используют промежуточный фасадный http-сервер, например, Apache или nginx, который слушает подключения на 80м порте, перенаправляет запросы спрятанному за фаерволом веб-приложению на Java, получает от него ответ и возвращает результат обратно в большой мир. Первоначальной причиной такого подхода была какая-то странная особенность Явы, которая кажется не умела слушать подключения с младших портов, если работала не в режиме рута (администратора), в детали не вникал. Так или иначе, иметь подобный фасад все равно полезно, т.к. традиционный легковесный http-сервер гораздо лучше справляется с распределением нагрузки, отдачей статического контента и имеет прочие оптимизации для повседневного веба, поэтому подобного рода работу (например, раздачу картинок для сайта) лучше по возможности скинуть на него, а веб-приложению оставить обслуживать динамику.

Итак, настроим веб-сервер nginx фасодом к нашему веб-приложению на Scala+Unfiltered, запущенному на виртуальной машине Java.

На виртуальной машине в облаке, устанавливаем nginx:

] sudo apt-get install nginx

Правим конфиг для фасада (здесь также предполагается, что к серверу также привязано доменное имя robotc.lasto4ka.su):

] sudo nano /etc/nginx/sites-available/robotc.lasto4ka.su

server {
        listen 80;

        root /usr/share/nginx/html;
        index index.html index.htm;

        # Make site accessible from http://localhost/
        server_name robotc.lasto4ka.su;

        access_log  /var/log/nginx/robotc.access.log;

        location / {
                proxy_redirect off;
                proxy_pass http://127.0.0.1:8080;

                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}



Включаем конфиг в nginx:
] cd /etc/nginx/sites-enabled/
] sudo ln -s ../sites-available/robotc.lasto4ka.su
] sudo /etc/init.d/nginx restart

Всё, теперь по адресу robotc.lasto4ka.su мы должны увидеть наше веб-приложение Scala+Unfiltered с любого компьютера или мобильного устройства, у которого есть доступ в интернет.

Фоновый сервис с веб-приложением конечно тоже должен быть запущен, порт 80 виртуальной машины открыт для всеобщего доступа, а порт 8080 на всякий случай можно и закрыть.


исходники занятия, подсветка синтаксиса.