Разработка сервера приложений
Дипломный
проект
Разработка
сервера приложений
АННОТАЦИЯ
информационный программный
приложение
Данная выпускная квалификационная работа
посвящена вопросам разработки сервера приложений для ИП «Баяртуев Д.Б.».
В проекте были использованы известные в
настоящее время технологии проектирования и средства разработки приложений, а
именно: интегрированная среда разработки Intellij
IDEA, средства
проектирования IBM
Rational
Rose и BPWin.
В рамках проекта выполнены анализ предметной
области, построена функциональная модель «Как надо», диаграмма прецедентов,
диаграмма последовательности действий, диаграмма классов, разработано
программное приложение.
Пояснительная записка содержит все необходимые
разделы и части.
ВВЕДЕНИЕ
В настоящее время активно растёт сложность
разработки и сопровождения информационных систем. Со временем могут появиться
потребности в функционале, который не был предусмотрен первоначальной
реализацией информационной системы. Кроме того, необходимый функционал не
всегда возможно реализовать средствами одного языка программирования.
Выделение нового уровня в архитектуре, коим
является сервер приложений, решает выше описанные проблемы. Внедрение сервера
приложения позволяет существенно повысить функциональность и производительность
готовой информационной системы, позволяя избежать изменений последней.
Разрабатываемый в данной работе сервер
приложений предназначен для ИП «Баяртуев Д.Б.». В результате работы ИП
«Баяртуев Д.Б.» получит универсальное средство, позволяющее управлять бизнес-логикой,
которая может быть реализована и дополнена новым функционалом путём написания
модулей-приложений.
Целью дипломного проекта является повышение
эффективности и функциональности готовой информационной системы.
Для достижения указанной цели в соответствии
объектом исследования поставлены следующие задачи:
) изучение и анализ предметной области;
) разработка функциональной модели «Как надо»;
) проектирование сервера приложения:
разработка диаграммы прецедентов;
разработка диаграммы последовательности действий
разработка диаграммы классов.
) реализация сервера приложения:
разработка программных модулей системы;
тестирование сервера приложений.
1. АНАЛИЗ
ТРЕБОВАНИЙ
.1 Описание
предметной области задачи
Информационная система «Бурятия.INFO»
представляет собой сайт справочник компаний города Улан-Удэ. Пользователь сайта
обладает возможностью создать страницу для своей компании, на который другие
пользователи могут оставлять отзывы и комментарии.
Проект «Бурятия.INFO»
рассчитан на широкую аудиторию, и предназначен в первую очередь для клиентов
компаний, отзывы о которых размещаются на сайте. «Бурятия.INFO»
это саморегулирующееся сообщество, где каждый пользователь может определённым
образом повлиять на рейтинг компаний, других пользователей, вступить в
обсуждение либо дискуссию с пользователями сайта.
Функционал сайта постоянно расширяется, что
позволяет привлекать в сообщество новых людей, в тоже время, поддерживая
интерес у “завсегдатаев сайта”. В следствии постоянно растущей динамики
изменений понадобилось универсальное средство, способное решать большинство
задач, связанных с описанным выше расширением функционала. В результате, было
принято решение о выделении дополнительного архитектурного уровня - сервера
приложений, способного обеспечить эффективную и удобную схему
модулей-приложений.
Сервер приложений должен обрабатывать запросы
сгенерированные браузером-клиентом, исполнять приложение, и отсылать результат
обратно. Все клиентские запросы проходят верификацию, прежде чем поступить на
сервер.
Сам сайт «Бурятия.INFO»
написан на языке программирования PHP.
В качестве веб-сервера используется Apache.
Так же, на стороне клиента используется javascript
библиотека jQuery,
представляющая удобные средства взаимодействия с клиентом-браузером.
После внедрения сервера приложений в
информационную систему «Бурятия.INFO»
заказчик получить гибкое, эффективное средство, которое позволит без изменений
в архитектуре и исходном коде приложения расширять функционал информационной
системы путём построения дополнительных модулей.
.2 Построение
функциональной модели «Как надо»
Проведённый анализ предметной области позволяет
приступить к построению функциональной модели «Как надо».
Контекстная диаграмма функциональной модели «Как
надо» имеет вид, представленный на рисунке 1.1.
Рисунок 1.1 - Контекстная диаграмма в
функциональной модели «Как надо»
Поток «AJAX
запрос» представляет собой запрос, сгенерированный клиентом-браузером.
Поток «Ответ сервера»представляет собой набор
данных, сформированных приложением, которые подлежат отправке клиенту.
Дальнейшая детализация контекстной диаграммы
показана на рисунке 1.2.
Рисунок 1.2 - Детализация контекстной диаграммы
«Обработка входящего соединения» включает в себя
процессы, отвечающие за установку соединения, чтение данных и т.д. Детализация
этого процесса представлена на рисунке 1.3.
«Обслуживание» - процесс, отвечающий за запуск
приложения и его исполнение. Детализация этого процесса представлена на рисунке
1.6.
Рисунок 1.3 - Процесс «Обработка входящего
соединения»
«Установка, соединение и чтение данных» отвечает
за работу с клиентом на TCP
уровне. Детализация этого процесса представлена на рисунке 1.4
«Инициализация работы приложения» - служебный
процесс, управляющий взаимодействием процессов «Обработка входящего соединения»
и «Обслуживание». Детализация этого процесса представлена на рисунке 1.5.
Рисунок 1.4 - Процесс «Установка, соединение и
чтение данных»
«Установка соединения» - устанавливает TCP
соединение с клиентом, которое используется далее для обмена информацией.
«Фильтрация соединения» - специальные фильтры,
такие как “чёрные” и “белые” списки. «Чтение данных» - после успешной
фильтрации, процесс читает поступающие от клиента данные.
Рисунок 1.5 - Процесс «Инициализация работы
приложения»
«Запуск исполнения» - процесс, отвечающий за
запуск приложения, выделение ресурсов и передачу параметров приложения.
«Завершение исполнения» освобождает ресурсы,
связанные с приложением, и передаёт сформированный приложением набор данных для
записи ответа.
Рисунок 1.6 - Процесс «Обслуживание»
«Обработка» включает в себя извлечение служебных
данных и запись их в структуру. Детализация этого процесса представлена на
рисунке 1.7
«Исполнение» - процесс, занимающийся
непосредственно запуском приложения, указанного в запросе. Детализация этого
процесса представлена на рисунке 1.8.
Рисунок 1.7 - Процесс «Обработка»
«Извлечение служебных данных» - процесс, который
занимается обработкой поступившего массива данных, то есть поиском служебных
данных и проверкой их правильности.
«Запись данных в структуру» - запись данных в
специальную программную структуру.
Рисунок 1.8 - Процесс «Исполнение»
«Поиск приложения» - поиск приложения в среде
развёртывания: в списке загруженных приложений, в кэше, на локальном диске.
«Исполнение приложения» - запуск приложения, и
передача ему указанных в запросе параметров.
2. ПРОЕКТИРОВАНИЕ
СИСТЕМЫ
.1 Проектирование
диаграммы прецедентов
В рамках дипломного проектирования разработаны
диаграмма классов, диаграмма прецедентов и диаграмма последовательности
действий. При разработке диаграмм было использовано Case-средство
IBM Rational
Rose.
Диаграмма прецедентов представлена на рисунке
2.1
Рисунок 2.1 - Диаграмма прецедентов
На диаграмме представлено три актёра:
Администратор - отвечает за настройку сервера,
отдаёт команды на запуск и остановку последнего. Связанные процессы: “Настроить
сервер”, “Запустить сервер приложений” и “Остановить сервер”.
Виртуальная машина является посредником между
Администратором и сервером приложений. После обращения администратора к
процессам “Запустить сервер приложений” и “Остановить сервер” контроль над
работой сервера передаётся виртуальной машине. Она, в свою очередь, исполняет
приложение в собственном контексте.
Сервер приложений - актёр, который занимается
обработкой поступающих на сервер запросов. Связанные процессы: “Обработать
запрос” и “Развернуть приложение”.
На выше описанной диаграмме представлены все
основные актёры и процессы, участвующие в работе разрабатываемой информационной
системе «Сервер приложений». Далее будет рассмотрена диаграмма
последовательности действий, изображённая на рисунке 2.2.
.2 Проектирование
диаграммы последовательности действий
Рисунок 2.2 - Диаграмма последовательности
действий
Диаграмма последовательности действий призвана
наглядно отобразить набор процессов, их последовательность и взаимодействие.
Ниже будут описаны все объекты изображённые на рисунке 2.2.
Обработчик соединений - объект, который отвечает
за установку соединений. Также занимается фильтрацией и закрытием соединений.
Тесно взаимодействует с системой ввода\вывода.
Система ввода\вывода занимается чтением и
записью данных, используя полученное соединение. После чтения передаёт данные в
специальный обработчик.
Обработчик данных извлекает служебные данные из
массива байт, полученного на этапе чтения данных. С помощью обработанных данных
производится запуск приложений на сервере приложений.
Модуль запуска приложений занимается
непосредственным запуском приложений, для чего использует служебные данные,
полученные на этапе обработки. После завершения работы приложения отправляет
сформированное последним сообщение в систему ввода\вывода, где происходит
запись ответа клиенту.
.3 Проектирование
диаграммы классов
Рисунок 2.3 - Диаграмма классов
На диаграмме классов представлены классы,
используемые приложением, и их взаимодействие. Представленные на диаграмме
классы:- класс, осуществляющий управление сервером на уровне приложения.-
интерфейс, который определяет поведение графических оболочек.- конкретная
реализация интерфейса VIewInterface, которая представляет графический интерфейс
пользователя в виде стандартной консоли.- перечисление, представляющее набор
команд, распознаваемых сервером.- TCP сервер, занимающийся обработкой
соединений.- фабрика, определяющая модель обработки соединений.
Классы пакета handlers представляют этапы
обработки соединения.- объект сессии, сформированный на уровне транспортного
протокола. Служит для хранения соединения и полученных данных.- контейнер,
который занимается хранением объектов класса Session.- рабочий класс,
определяющий цикл обработки запросов. Занимается выборкой сессий из
SessionController, и передачей их на дальнейшую обработку.- класс, определяющий
логику обработки данных бизнес процессами.- класс обработки данных, занимается
извлечением и систематизацией данных.- служебная структура, хранящая
обработанные данные.- класс, занимающийся вызовом приложений, размещённых на
сервере.- внутренний кэш. Хранит служебные данные, необходимые для вызова
приложений.
3. РЕАЛИЗАЦИЯ
ПРОЕКТА
.1 Выбор средств
разработки
Для разработки информационной системы
использован язык Java
и визуальная среда разработки IntelliJ IDEA.-
объектно-ориентированный язык программирования, разработанный компанией Sun
Microsystems (в последующем приобретённой компанией Oracle). Приложения Java
обычно компилируются в специальный байт-код, поэтому они могут работать на
любой виртуальной Java-машине (JVM) вне зависимости от компьютерной
архитектуры. Java прекрасно зарекомендовал себя разработке высоконагруженных
серверных приложений. API языка представляет достаточно широкий спектр удобных
средств для обработки информации, работы с сокетами и многопоточного
программирования.
IntelliJ IDEA - коммерческая
интегрированная cреда разработки программного обеспечения на многих языках
программирования, в частности Java, JavaScript, Python и др., разработанная
компанией JetBrains.Таким образом, анализ возможностей языка показал, что его
можно использовать для решения данной задачи. IntelliJ IDEA хорошо совместима
со многими популярными свободными инструментами разработчиков, такими как CVS, Subversion,
Apache Ant,
Maven и JUnit.
Начиная с версии 9.0, IntelliJ
IDEA доступна в двух
версиях: Community
Edition и Ultimate
Edition. Community Edition
является полностью свободной версией, доступной под лицензией Apache
2.0. В ней реализована полная поддержка Java
SE, Groovy,
Scala, а также
интеграция с наиболее популярными системами управления версиями. В версии
Ultimate Edition реализована поддержка Java
EE, UML
-диаграмм, подсчет покрытия кода, а также поддержка других систем управления
версиями, языков и фреймворков.
Для управления работы приложения на транспортном
уровне был выбран фреймворк Netty. Netty
- асинхронно-событийный сетевой фреймворк, служащий для быстрой разработки
высокопроизводительных протоколов для серверов и клиентов. Netty позволяет
достаточно быстро развернуть многопоточное серверное приложение, а так же
предоставляет удобные средства для работы с соединениями и их обработки.
.2 Архитектура
программы
В архитектурном решении программы использовались
основные принципы построения сервера приложений. Введем понятие «Сервер
приложений».
Сервер приложений (англ. application server) -
это программная платформа (software framework), предназначенная для
эффективного исполнения процедур (программ, механических операций, скриптов),
которые поддерживают построение приложений. Сервер приложений действует как
набор компонентов, доступных разработчику программного обеспечения через API
(Интерфейс прикладного программирования), который определен самой платформой.
Для веб-приложений эти компоненты обычно
работают на той же машине, где запущен веб-сервер. Их основная работа -
обеспечивать создание динамических страниц. Однако современные серверы
приложений больше ориентированы на то, чтобы выполнять такие сервисы как
кластеризация, отказоустойчивость и балансировка нагрузки, позволяя, таким
образом, разработчикам сфокусироваться только на реализации бизнес-логики. Для
более наглядного представления архитектуры была разработана её схема,
изображённая на рисунке 3.1
Рисунок 3.1 - Архитектура программы
Клиент - браузер, который формирует запросы к
серверу приложений.
Приложение - программная единица, исполняемая в
контексте сервера приложений и реализующая бизнес-логику.
Управление данными - часть сервера приложений,
которая взаимодействует с хранилищами, управляет процессами добавлением,
изменением и удалением данных.
База данных - предметно-ориентированная
информационная база данных.
Детальная схема, на которой изображено более
подробное представление архитектуры сервера приложений, описана ниже (рисунок
3.2).
Рисунок 3.2 - Детальная схема
Транспортный уровень - включает обработку
соединений и чтение данных. Обработка соединений происходить под управлением
фреймворка Netty, которые
использует специальные фильтры. После успешной установки соединений происходит
чтение данных.
Обработка данных - включает извлечение служебных
данных, таких как имя пользователя и данные о параметрах приложений.
Инициализация приложения - включает поиск
приложения и инициализацию параметров. Поиск приложения сначала обращается к
внутри программному кэшу. В случае если приложение не было найдено в кэше,
производится поиск по пространству имён приложения. После производится
инициализация параметров, которая включает в себя создание экземпляров на
основе данных, переданных в запросе.
Запуск приложения - включает менеджер ресурсов,
который выделяет ресурсы на выполнение приложения. После результат выполнения
приложения отправляется клиенту в качестве ответа. Менеджер ресурсов занимается
выделением и освобождением ресурсов для приложений, частично управляет
контекстом исполнения.
.3 Графический
интерфейс пользователя
Интерфейс программы выполнен в стиле консольного
приложения. Для взаимодействия используются простые текстовые команды. После
запуска приложения будет отображено окно приветствия, представленное на рисунке
3.3.
Рисунок 3.3 - Запуск приложения
Для получения информации о предоставляемых
командах управления, можно воспользоваться справкой, которая вызывается
посредством команды “-help”
(рисунок 3.4)
Рисунок 3.4 - Запуск справки
Как видно из подсказки, для запуска сервера
нужно воспользоваться командой “-start”
(рисунок 3.4). После подачи команды в окно приложения будет выведена служебная
информация.
Рисунок 3.5 - Запуск сервера
3.4 Тестирование программного изделия
После запуска сервера приложений с помощью
команды “-start” станет
возможным обращение к последнему со стороны клиента. Работу сервера можно
протестировать с помощью специального приложения, которое будет отправлять
заранее сформированный запрос. После его выполнения можно сравнить полученный
ответ с правильным результатом. Запрос, отправляемый приложением, представлен
ниже:
{
"methodName":”com.gmail.dosofredriver.ajax.serviceserver.Test.summarize",
"params" : [
{
"type" : "int",
"value" : "1"
}
{
"type" : “int”,
"value"
: "3"
}
]
}
Здесь “summarize”
- это приложение, которое возвращает значение суммы переданных параметров. Как
видно из запроса, результатом выполнения этого приложения должно быть число
четыре. Результаты запуска приложения представлены на рисунке 3.6.
Рисунок 3.6 - Результаты запуска тест приложения
Результат выполнения полностью совпадает с
суммой переданных параметров, из чего следует, что сервер приложений корректно
обработал полученный запрос.
4. ДОКУМЕНТИРОВАНИЕ
.1 Руководство
пользователя
.1.1 Характеристика и назначение программы
Программа представляет собой консольное Java-приложение.
Для работы с данной программой пользователь должен иметь навыки работы с
операционными системами Windows XP.
.1.2 Требования к программе
Минимальный состав средств вычислительной
техники и программного обеспечения для установки клиентского приложения:
процессор Pentium и выше;
оперативная память не менее 128 MB;
дисковое пространство для установки клиентского
приложения - 10 МB;
виртуальная машина Java;
операционная система с поддержкой Java
SE 1.5.
Эти величины в действительности являются только
минимумом. Чем выше быстродействие процессора и больше объем памяти, тем выше
производительность компьютера, а, следовательно, и приложения. Также необходимо
учесть, что для выполнения некоторых приложений может понадобиться
дополнительное программное обеспечение, например, система управления базами
данных.
.1.3 Программные команды
Для управления работой программы используются
специальные управляющие команды. Ниже представлено их описание.
start - производит
запуск сервера приложений;
stop -
производит остановку сервера приложений;
restart
- производит перезапуск сервера приложений;
help - вызов
справки.
.1.4 Параметры запуска
Параметры запуска используются для более
эффективной инициализации приложения. Ниже представлены реализованные параметры
запуска.
configpath:<value>
- указывает системный путь к конфигурационному файлу.
autostart
- указывает приложению о необходимости запуска сервера приложений
непосредственно после запуска.
.1.5 Конфигурационный файл
Конфигурационный файл представляет собой
служебный файл, в котором задаются настройки сервера приложений. Стандартный
путь к конфигурационному файлу соответствует значению /config/config.txt
(относительный путь), и изменяется путём задачи специального параметра запуска configpath,
описанного выше. Ниже представлены возможные конфигурационные значения, и их
описание.
server-pool-size
- определяет размер пула потоков исполнения, отвечающих за управление
соединениями. С помощью этого параметра можно влиять на производительность
сервера приложений (вертикальное масштабирование);
worker-pool-size
- определяет размер пула потоков исполнения, отвечающих за исполнения
приложений. С помощью этого параметра можно влиять на производительность
сервера приложений (вертикальное масштабирование);
server-port
- определяет порт, на котором будет работать сервер приложений;
server-ip
- определяет IP, на котором
будет работать сервер приложений;
log-name
- задаёт имя лог-файла;
blacklist
- данная опция позволяет подключить чёрный список;
whitelist
- данная опция позволяет подключить белый список;
whitelist-path
- определяет путь к белому списку, если используются нестандартные пути;
blacklist-path
- определяет путь к чёрному списку, если используются нестандартные пути;
.1.6 Лог-файл
Лог-файл - специальный файл, который облегчает
работу администратора с сервером приложений. В лог-файл записываются служебная
информация, сведения об ошибках времени выполнения и т.д. Лог-файл выполнен в
формате HTML. Всего
существует три уровня сообщений: INFO,
WARNING, SEVERE.
INFO - такой
меткой помечается служебная информация, например, сообщение а запуске
приложения, сетевой порт.
WARNING
- эта метка указывает на некритичные ошибки выполнения. Выделяется серым
цветом.
SEVERE - указывает
на критические ошибки выполнения, после которых, зачастую, нормальное
функционирование сервера невозможно. Часто помогает в отладке. Выделяется
красным цветом.
.1.7 Чёрный и белый списки
Чёрный и белый списки служат для фильтрации
входящих соединений. Например, если на сервер поступает запрос с IP-адреса,
указанного в чёрном списке, то при включенной опции чёрного списка такой запрос
будет отброшен. Аналогично работает белый список, с той лишь разницей, что он
отбрасывает запросы с адресов, не указанных в списке.
ЗАКЛЮЧЕНИЕ
В дипломном проекте поставлена и решена задача
реализации сервера приложений для ИП «Баяртуев Д.Б.». Внедрение данного проекта
позволит в значительной степени повысить функциональность и производительность
существующей информационной системы за счёт выделения нового уровня в
архитектуре готовый ИС, котором является сервер приложений.
В работе разработана функциональная модель «Как
надо», разработаны диаграммы прецедентов, классов, и последовательности
действий. Разработано программное приложение, реализующее весь необходимый
функционал.
Использование информационной системы в ИП
«Баяртуев Д.Б.» позволит сотрудникам компании получить ряд конкретных
преимуществ: увеличить скорость разработки модулей, и расширения функционала,
сократить время на тестирование и отладку приложений. Также, сотрудники
получают в свою распоряжение универсальную и надёжную систему, удобную в
использовании.
СПИСОК
ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Андон Ф., Резниченко В. Язык
запросов SQL. Учебный курс. - СПб.: Питер, 2006. - 416 с.
2. Горбунов-Посадов М.М. Расширяемые
программы. - М.: Полиптих, 1999. - 336 с
3. Герберт Шилдт. Java. Полное
руководство. Java SE 7 = Java 7: The Complete
Reference. - 8-е изд.
- М.:
Вильямс,
2012. - 1104 с.
4. Давыдов,
С.,
Ефимов,
А.
IntelliJ IDEA. Профессиональное программирование на
Java (В Подлиннике). -
1-е изд. - СПб.: BHV.
- 800 с.
5. Wikipedia.org
[Сайт].
- URL:
ПРИЛОЖЕНИЕ
package
com.gmail.dosofredriver.ajax.serviceserver;com.gmail.dosofredriver.ajax.serviceserver.server.TCPServer;com.gmail.dosofredriver.ajax.serviceserver.service.worker.Worker;com.gmail.dosofredriver.ajax.serviceserver.util.configure.Configurator;com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;com.gmail.dosofredriver.ajax.serviceserver.util.view.ConsoleView;com.gmail.dosofredriver.ajax.serviceserver.util.view.ViewInterface;java.io.BufferedReader;java.io.IOException;java.io.InputStreamReader;java.util.logging.Level;
/**
* Date: 06.03.13
* Time: 22:54
*
* @author DoSOfRR
*/class Commander {static final
String DEFAULT_CONFIG_PATH = "config/config.txt";String configPath =
DEFAULT_CONFIG_PATH;ViewInterface view;ServerLogger logger;TCPServer
server;Thread serverThread;Thread workerThread;Worker worker;boolean autoStart
= false;boolean isLogged = false;Commander(ViewInterface view, String ... args)
{.view = view;(args);
}void init(String ... args)
{{(args);config = new Configurator(configPath);= config.getConfiguredLogger();=
config.getConfiguredServer();=
config.getConfiguredWorker();.setLogger(logger);.setLogger(logger);.setFilter(config.getConfiguredFilter());(logger
!= null) {= true;.setLogger(logger);
}(autoStart) {.startServer();
}
} catch (Exception e)
{.err.println("An error occupied while initializing server: \n" + e);
}
}void parseArgs(String ... args)
{(String arg : args) {value = null;type;(arg.contains(":")) {=
arg.substring(0, arg.indexOf(':'));= arg.substring(arg.indexOf(':')+1,
arg.length());
} else {= arg;
}(type) {"configpath" : configPath
= "value"; break;"autostart" : autoStart = true; break;:
{.out.println("Option " + value + " is not
supported!");.exit(0);
}
}
}
}void startServer() {= new
Thread(new Runnable() {
@Overridevoid run() {.start();
}
});= new Thread(new Runnable() {
@Overridevoid run() {{.start();
//todo ex
} catch (InterruptedException e)
{.log(Level.SEVERE, "Can not start worker!", e);
}
}
});.setDaemon(true);.start();.setDaemon(true);.start();
}void stopServer()
{{.stop();.interrupt();.stop();.interrupt();
} catch (InterruptedException e)
{.log(Level.WARNING, "An error occupied while stopping server", e);
}
}boolean deploy() {false;
}
/*
* This is a default program entry
point.
*/static void main(String ... args)
{commander = new Commander(new ConsoleView(), args);br = new BufferedReader(new
InputStreamReader(System.in));run = true;
{.view.showDefault();
} catch (IOException e)
{.printStackTrace();
}(run) {[] message;{=
br.readLine().getBytes();(commander.view.readMessage(message)) {Help :
commander.view.showHelp(); break;Start_Server : commander.startServer();
break;Stop_Server : commander.stopServer(); break;Undefined :
commander.view.showMessage("Undefined command."); break;Exit : run =
false; break;: commander.view.showMessage("Not supported yet.");
}
} catch (IOException e)
{.printStackTrace();
}
}
}
}com.gmail.dosofredriver.ajax.serviceserver.server;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;com.gmail.dosofredriver.ajax.serviceserver.server.pipeline.ServerPipelineFactory;com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;org.jboss.netty.bootstrap.ServerBootstrap;org.jboss.netty.channel.Channel;org.jboss.netty.channel.ChannelFuture;org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;java.net.InetSocketAddress;java.util.concurrent.ExecutorService;java.util.concurrent.Executors;java.util.logging.Level;
/**
* Date: 25.02.13
* Time: 23:47
*
* @author DoSOfRR
*/class TCPServer {static final
String DEFAULT_IP_ADDRESS = "127.0.0.1";static final int DEFAULT_POOL_SIZE
= 4;static final int DEFAULT_PORT = 777;ServerPipelineFactory
serverPipeline;ServerBootstrap server;ServerLogger logger;Channel
mainChannel;String address;boolean isStarted = false;boolean isLogged =
false;int poolSize;int port;TCPServer() {(DEFAULT_PORT, DEFAULT_POOL_SIZE,
DEFAULT_IP_ADDRESS);
}TCPServer(int port) {(port,
DEFAULT_POOL_SIZE, DEFAULT_IP_ADDRESS);
}TCPServer(int port, int poolSize)
{(port, poolSize, DEFAULT_IP_ADDRESS);
}TCPServer(int port, int poolSize,
String address) {.port = port;.address = address;.poolSize = poolSize;= new
ServerPipelineFactory();
}void start() {
(!isStarted) {{bossExec =
Executors.newFixedThreadPool(1);workExec =
Executors.newFixedThreadPool(poolSize);= new ServerBootstrap(new
NioServerSocketChannelFactory(bossExec, workExec,
poolSize));.setOption("backlog", 500); //todo
config.setOption("connectTimeoutMillis",
10000);.setPipelineFactory(serverPipeline);= server.bind(new InetSocketAddress(address,
port));= true;(isLogged) {.log(Level.INFO, "Server started on " +
port + " port.");
}.out.println("Server started
on " + port + " port.");
} catch (Exception e) {(isLogged)
{.out.println("An error occupied while starting server. See log for more
info.");.log(Level.SEVERE, "An error occupied while starting
server.", e);
} else {.out.println("An error
occupied while starting server. \n" + e);
}
}
} else {.out.println("Server is
already started!");
}
}void stop() {(isStarted) {future =
mainChannel.close();.awaitUninterruptibly();.shutdown();= false;(isLogged)
{.log(Level.INFO, "Server was manually stopped.");
}.out.println("Server
stopped.");
} else {.out.println("Server is
not started!");
}
}ServerLogger getLogger() {logger;
}void setLogger(ServerLogger logger)
{(logger == null) {new NullPointerException("Logger can not be
null!");
}.logger = logger;= true;
}void setFilter(ConnectionFilter
filter) throws Exception {.getPipeline().addFirst("Filter", filter);
}
}com.gmail.dosofredriver.ajax.serviceserver.server.session;org.jboss.netty.channel.Channel;java.nio.ByteBuffer;
/**
* Date: 02.03.13
* Time: 19:13
*
* @author DoSOfRR
*/class Session {ByteBuffer
data;Channel channel;Session(ByteBuffer data, Channel channel)
{.setChannel(channel);.setData(data);
}ByteBuffer getData() {data;
}void setData(ByteBuffer data)
{.data = data;
}Channel getChannel() {channel;
}void setChannel(Channel channel)
{.channel = channel;
}
}com.gmail.dosofredriver.ajax.serviceserver.server.session;org.jboss.netty.channel.ChannelFuture;org.jboss.netty.channel.ChannelFutureListener;org.jboss.netty.channel.Channels;java.util.concurrent.BlockingQueue;java.util.concurrent.LinkedBlockingQueue;
/**
* Date: 27.02.13
* Time: 14:42
*
* @author DoSOfRR
*/class SessionController
{BlockingQueue<Session> store;static SessionController ourInstance = new
SessionController();static SessionController getInstance() {ourInstance;
}SessionController() {= new
LinkedBlockingQueue<>();
}void putSession(Session session)
throws InterruptedException {.put(session);
}void response(Session session)
{future = Channels.write(session.getChannel(),
session);.addListener(ChannelFutureListener.CLOSE);
}Session getSession() throws
InterruptedException {store.take();
}
}com.gmail.dosofredriver.ajax.serviceserver.server.pipeline;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.DataReader;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.Decoder;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.Encoder;org.jboss.netty.channel.ChannelPipeline;org.jboss.netty.channel.ChannelPipelineFactory;org.jboss.netty.channel.Channels;
/**
* Date: 26.02.13
* Time: 23:26
*
* @author DoSOfRR
*/class ServerPipelineFactory
implements ChannelPipelineFactory {
@OverrideChannelPipeline
getPipeline() throws Exception {filter = new ConnectionFilter();
//todo configresult =
Channels.pipeline(new Decoder(), new Encoder(), new DataReader());result;
}
}com.gmail.dosofredriver.ajax.serviceserver.server.handlers;org.jboss.netty.channel.ChannelEvent;org.jboss.netty.channel.ChannelHandlerContext;org.jboss.netty.channel.SimpleChannelUpstreamHandler;java.io.BufferedReader;java.io.FileReader;java.io.IOException;java.util.HashSet;java.util.Set;
/**
* Date: 26.02.13
* Time: 14:49
*
* @author DoSOfRR
*/class ConnectionFilter extends
SimpleChannelUpstreamHandler {static final String DEFAULT_WHITELIST_PATH =
"config/whitelist.txt";static final String DEFAULT_BLACKLIST_PATH =
"config/blacklist.txt";static final int WHITELIST_ON = 0;static final
int BLACKLIST_ON = 1;static final int WHITELIST_OFF = 3;static final int
BLACKLIST_OFF = 4;final Set<String> whiteList = new
HashSet<>();final Set<String> blackList = new HashSet<>();String
whiteListPath;String blackListPath;boolean isWhiteListOn;boolean
isBlackListOn;ConnectionFilter() {= false;= false;= DEFAULT_WHITELIST_PATH;=
DEFAULT_BLACKLIST_PATH;
}void setOption(int list, String
listPath) throws IllegalArgumentException, IOException {(list) {BLACKLIST_ON:
{= listPath;= true;
} break;WHITELIST_ON: {= listPath;=
true;
} break;: throw new
IllegalArgumentException();
}();
}void setOption(int list) throws
IllegalArgumentException, IOException {(list) {BLACKLIST_ON: isBlackListOn =
true; break;WHITELIST_ON: isWhiteListOn = true; break;BLACKLIST_OFF:
isBlackListOn = false; break;WHITELIST_OFF: isWhiteListOn = false; break;:
throw new IllegalArgumentException();
}();
}boolean reloadLists() throws
IOException {();true;
}
@Overridevoid
handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception
{addr;= ctx.getChannel().getRemoteAddress().toString();= addr.substring(1,
addr.indexOf(':'));(isBlackListOn) {(blackList.contains(addr))
{.getChannel().close(); //rejects incoming connection
}
}(isWhiteListOn)
{(!whiteList.contains(addr)) {.getChannel().close(); //rejects incoming
connection
}
}
}void loadList() throws IOException
{br;line;(isBlackListOn) {= new BufferedReader(new
FileReader(blackListPath));((line = br.readLine()) != null) {.add(line);
}
}(isWhiteListOn) {= new
BufferedReader(new FileReader(whiteListPath));((line = br.readLine()) != null)
{.add(line);
}
}
}
}com.gmail.dosofredriver.ajax.serviceserver.server.handlers;com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;com.gmail.dosofredriver.ajax.serviceserver.server.session.SessionController;org.jboss.netty.channel.ChannelHandlerContext;org.jboss.netty.channel.ExceptionEvent;org.jboss.netty.channel.MessageEvent;org.jboss.netty.channel.SimpleChannelUpstreamHandler;
/**
* Date: 26.02.13
* Time: 23:51
*
* @author DoSOfRR
*/class DataReader extends
SimpleChannelUpstreamHandler {
@Overridevoid messageReceived(final
ChannelHandlerContext ctx, MessageEvent e) throws Exception {message =
e.getMessage();(message instanceof Session)
{.getInstance().putSession((Session) message);
}
}
@Overridevoid
exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
//todo log
exception.err.println("Err from: " + e.getChannel().getRemoteAddress());.getChannel().close();
}
}com.gmail.dosofredriver.ajax.serviceserver.server.handlers;com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;org.jboss.netty.buffer.ChannelBuffer;org.jboss.netty.channel.Channel;org.jboss.netty.channel.ChannelHandlerContext;org.jboss.netty.handler.codec.oneone.OneToOneDecoder;java.nio.ByteBuffer;
/**
* Date: 27.02.13
* Time: 2:07
*
* @author DoSOfRR
*/class Decoder extends
OneToOneDecoder {int length;
@OverrideObject
decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception
{(msg instanceof ChannelBuffer) {data = ByteBuffer.wrap(((ChannelBuffer)
msg).array());new Session(data, channel);
}null;
}
}com.gmail.dosofredriver.ajax.serviceserver.server.handlers;com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;org.jboss.netty.buffer.ChannelBuffers;org.jboss.netty.channel.Channel;org.jboss.netty.channel.ChannelHandlerContext;org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
* Date: 02.03.13
* Time: 19:06
*
* @author DoSOfRR
*/class Encoder extends
OneToOneEncoder {
@OverrideObject
encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception
{(msg instanceof Session) {ChannelBuffers.wrappedBuffer(((Session)
msg).getData());
} else {ChannelBuffers.EMPTY_BUFFER;
} //note the writer should manually
close channel after the message walk through pipeline
}
}com.gmail.dosofredriver.ajax.serviceserver.service;com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;com.gmail.dosofredriver.ajax.serviceserver.util.invoke.Invoker;com.gmail.dosofredriver.ajax.serviceserver.util.parser.Parser;java.nio.ByteBuffer;
/**
* Date: 07.03.13
* Time: 21:19
*
* @author DoSOfRR
*/class Service {static Session
service(Session session) throws Exception {request = new
String(session.getData().array()); //get AJAX requestresult =
Invoker.invoke(Parser.parseRequest(request)); //parse it, and call application
new
Session(ByteBuffer.wrap(result.toString().getBytes()), session.getChannel());
//return new Session
}
}com.gmail.dosofredriver.ajax.serviceserver.service.worker;com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;com.gmail.dosofredriver.ajax.serviceserver.server.session.SessionController;com.gmail.dosofredriver.ajax.serviceserver.service.Service;com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;java.util.concurrent.ExecutorService;java.util.concurrent.Executors;java.util.concurrent.TimeUnit;java.util.logging.Level;
/**
* Date: 06.03.13
* Time: 21:04
*
* @author DoSOfRR
*/class Worker {static final int
DEFAULT_POOL_SIZE = 8;volatile boolean stopFlag = false;ExecutorService
executor;ServerLogger logger;boolean isLogged = false;Worker()
{(DEFAULT_POOL_SIZE);
}Worker(int pool_size) {(pool_size);
}void init(int pool_size) {= Executors.newFixedThreadPool(pool_size);
}void start() throws
InterruptedException {(isLogged) {.log(Level.INFO, "Worker
started.");
}= false;(!stopFlag) {Session
session = SessionController.getInstance().getSession();.execute(new Runnable()
{
@Overridevoid run() {{
SessionController.getInstance().response(Service.service(session));
} catch (Exception e) {(isLogged)
{.log(Level.SEVERE, "An error occupied while parsing request!",
e);.getChannel().close(); //note try to use AutoCloseable
}
}
}
});
}
}void stop() throws
InterruptedException {= true;.awaitTermination(10, TimeUnit.SECONDS); //note С…СѓР№
знает
почему
таски
работающие
РІРёСЃСЏС‚
:\(isLogged) {.log(Level.INFO, "Worker was manually stopped.");
}
}void setLogger(ServerLogger logger)
{(logger == null) {new NullPointerException("Logger can not be
null!");
}.logger = logger;= true;
}
}com.gmail.dosofredriver.ajax.serviceserver.service.annotations;
/**
* This exception указывает
for controller implementation error.
* Controller class must be annotated
with <code>ServiceClass</code> annotation.
*/class IsNotAnnotatedException
extends Throwable {String message;IsNotAnnotatedException() {= "Given
class or method is not annotated!";
}IsNotAnnotatedException(Throwable
ex) {(ex);= "Given class or method is not annotated!";
}IsNotAnnotatedException(String
message) {.message = message;
}IsNotAnnotatedException(String
message, Throwable ex) {(ex);.message = message;
}
}com.gmail.dosofredriver.ajax.serviceserver.service.annotations;
/**
* This annotation is used as marker
for all methods that should be invoked by
* <code>Service</code>
class.
*
* @see
com.gmail.dosofredriver.ajax.serviceserver.service.Service;
*/java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)@interface
ServiceMethod {
}com.gmail.dosofredriver.ajax.serviceserver.util.collections;java.util.Comparator;
/**
* Date: 29.03.13
* Time: 21:51
*
* @author DoSOfRR
*/class DefaultOrderComparator
implements Comparator {
@Overrideint compare(Object o1,
Object o2) {1;
}
}com.gmail.dosofredriver.ajax.serviceserver.util.configure;com.gmail.dosofredriver.ajax.serviceserver.server.TCPServer;com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;com.gmail.dosofredriver.ajax.serviceserver.service.worker.Worker;com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;java.io.File;java.io.FileInputStream;java.io.IOException;java.util.StringTokenizer;
/**
* Date: 26.04.13
* Time: 2:14
*
* @author DoSOfRR
*/class Configurator
{ConnectionFilter configuredFilter;ServerLogger configuredLogger;TCPServer
configuredServer;Worker configuredWorker;Configurator(String configPath) throws
IOException {(configPath);
}void init(String configPath) throws
IOException {data = readFile(configPath);(data == null) {();;
}(data);
}void parseConfig(String data)
throws IOException {whiteList_path =
ConnectionFilter.DEFAULT_WHITELIST_PATH;blackList_path =
ConnectionFilter.DEFAULT_BLACKLIST_PATH;server_ip = TCPServer.DEFAULT_IP_ADDRESS;log_name
= ServerLogger.DEFAULT_LOG_NAME;server_pool_size=
TCPServer.DEFAULT_POOL_SIZE;worker_pool_size=
Worker.DEFAULT_POOL_SIZE;server_port = TCPServer.DEFAULT_PORT;blackListOn =
false;whiteListOn = false;tokenizer = new StringTokenizer(data);(tokenizer.hasMoreTokens())
{line = tokenizer.nextToken();type = line.substring(0,
line.indexOf('='));value= line.substring(line.indexOf('=')+1,
line.length());(type.toLowerCase()) {"server-pool-size" :
server_pool_size = Integer.parseInt(value); break;"worker-pool-size"
: worker_pool_size = Integer.parseInt(value); break;"server-port" :
server_port = Integer.parseInt(value); break;"server-ip" : server_ip
= value; break;"log-name" : log_name = value; break;"blacklist"
: blackListOn = Boolean.parseBoolean(value); break;"whitelist" :
whiteListOn = Boolean.parseBoolean(value); break;"whitelist-path" :
whiteList_path = value; break;"blacklist-path" : blackList_path =
value; break;: System.err.println("Unknown config option - " +
value);
}.configuredWorker = new
Worker(worker_pool_size);.configuredServer = new TCPServer(server_port,
server_pool_size, server_ip);.configuredLogger = new
ServerLogger(ServerLogger.DEFAULT_NAME, log_name);.configuredFilter = new
ConnectionFilter();
//configure filter(blackListOn)
{.configuredFilter.setOption(ConnectionFilter.BLACKLIST_ON, blackList_path);
}(whiteListOn)
{.configuredFilter.setOption(ConnectionFilter.WHITELIST_ON, whiteList_path);
}
}
}String readFile(String configPath)
throws IOException {file = new File(configPath);fis;[] buffer;(!file.exists())
{null;
}= new FileInputStream(file);= new
byte[fis.available()];(int b, count = 0; (b = fis.read()) != -1; count++)
{[count] = (byte) b;
}new String(buffer);
}void setDefaults() throws
IOException {.configuredFilter = new ConnectionFilter();.configuredLogger = new
ServerLogger();.configuredServer = new TCPServer();.configuredWorker = new
Worker();
}ConnectionFilter
getConfiguredFilter() {configuredFilter;
}ServerLogger getConfiguredLogger()
{configuredLogger;
}TCPServer getConfiguredServer()
{configuredServer;
}
Worker getConfiguredWorker()
{configuredWorker;
}
}com.gmail.dosofredriver.ajax.serviceserver.util.invoke;java.lang.reflect.Method;java.util.concurrent.ConcurrentHashMap;
/**
* Date: 29.03.13
* Time: 1:48
*
* @author DoSOfRR
*/class InvokeCache {static
InvokeCache ourInstance = new InvokeCache();ConcurrentHashMap<String,
Class> cachedClasses = new ConcurrentHashMap();ConcurrentHashMap<String,
Method> cachedMethods = new ConcurrentHashMap();static InvokeCache
getInstance() {ourInstance;
}InvokeCache() {
}Method findMethod(String
methodName) {cachedMethods.get(methodName);
}Class findClass(String className)
{cachedClasses.get(className);
}boolean cacheMethod(Method method)
{(findMethod(method.toString()) == null) {.put(method.toString(), method);true;
} else {false;
}
}boolean cacheClass(Class clazz)
{(findClass(clazz.getName()) == null) {.put(clazz.getName(), clazz);true;
} else {false;
}
}void clearCache()
{.clear();.clear();
}
}com.gmail.dosofredriver.ajax.serviceserver.util.invoke;com.gmail.dosofredriver.ajax.serviceserver.service.annotations.ServiceMethod;com.gmail.dosofredriver.ajax.serviceserver.util.parser.MethodStruct;java.lang.reflect.Method;java.lang.reflect.Modifier;
/**
* Date: 28.03.13
* Time: 2:11
*
* @author DoSOfRR
*/class Invoker {static
IllegalArgumentException cachedException = new IllegalArgumentException(new
NullPointerException("Method can not be null!"));static Object
invoke(MethodStruct param) throws Exception { //todo check security
fuckupsmethodName =
param.methodName.substring(param.methodName.lastIndexOf(".")+1,
param.methodName.length());className = param.methodName.substring(0,
param.methodName.lastIndexOf("."));clazz = getClass(className);method
= getMethod(methodName, clazz, param.argsTypes);(method ==
null)cachedException;
//security
check(!method.isAnnotationPresent(ServiceMethod.class)) {new
SecurityException("Method is not annotated with ServiceMethod!");
}
//use another invoke type if method
is static(Modifier.isStatic(method.getModifiers()))
{method.invoke(clazz.getClass(), param.params.toArray());
} else
{method.invoke(clazz.newInstance(), param.params.toArray()); //todo create
method to get class instance?
}
}static Method getMethod(String
methodName, Class owner, Class [] params) throws NoSuchMethodException,
ClassNotFoundException {cache = InvokeCache.getInstance();result;((result =
cache.findMethod(methodName)) != null) { //try to find method in cacheresult;
} else {= owner.getMethod(methodName,
params);result;
}
}static Class getClass(String
className) throws ClassNotFoundException {cache =
InvokeCache.getInstance();result;((result = cache.findClass(className)) !=
null) {result;
} else {=
Class.forName(className);.cacheClass(result);result;
}
}
}com.gmail.dosofredriver.ajax.serviceserver.util.logger;java.io.PrintWriter;java.io.StringWriter;java.util.Date;java.util.logging.Formatter;java.util.logging.Handler;java.util.logging.Level;java.util.logging.LogRecord;
/**
* @author Урванов Ф. В.
* Класс, преобразующий лог в формат HTML.
*
*/HTMLFormatter extends Formatter {
/**
* Return head of HTML file.
*/
@OverrideString getHead(Handler h)
{
/**
* Write title, meta data and table.
*/"<html><head><title>AppLog</title>"
+
"<meta
http-equiv=\"content-type\" content=\"text/html;
charset=utf-8\">" +
"</head><body>"
+
"<table border=1>" +
"<tr
bgcolor=CYAN><td>date</td><td>level</td><td>class</td><td>method</td>"
+
"<td>message</td><td>thrown
message</td><td>stacktrace</td></tr>";
}
/**
* Return end of HTML file.
*/
@OverrideString getTail(Handler h)
{
/**
* Write end of table and HTML file.
*/"</table></body></html>";
}
/**
* Format message to table string.
*/
@OverrideString format(LogRecord
record)
{result=new StringBuilder();d = new
Date();level = record.getLevel();
/**
* Error will be highlighted with red
color,
* warnings with grey,
* info messages with white.
*/(level==Level.SEVERE)
{.append("<tr
bgColor=Tomato><td>");
}if (level==Level.WARNING)
{.append("<tr
bgColor=GRAY><td>");
}
{.append("<tr
bgColor=WHITE><td>");
}.append("\n");.append(d);.append("</td><td>");.append(record.getLevel().toString());.append("</td><td>");.append(record.getSourceClassName());.append("</td><td>");.append(record.getSourceMethodName());.append("</td><td>");.append(record.getMessage());.append("</td><td>")thrown
= record.getThrown();
if (thrown!=null)
{
// Если было передано исключение, то выводим
полный
// стек
вызовов..append(record.getThrown().getMessage());.append("</td><td>");sw
= new StringWriter();pw = new
PrintWriter(sw);.getThrown().printStackTrace(pw);stackTrace=sw.toString();.append(stackTrace);.append("</td>");
}
{
// Просто
пустые
ячейки..append("</td><td>null");.append("</td>");
}
// Конец
строки.append("</tr>\n");result.toString();
}
}com.gmail.dosofredriver.ajax.serviceserver.util.logger;java.io.IOException;java.util.logging.FileHandler;java.util.logging.Level;java.util.logging.Logger;
/**
* Date: 09.12.12
* Time: 22:15
*
* @author DoSOfRR
*/class ServerLogger {final static
String DEFAULT_LOG_NAME = "log.html";final static String DEFAULT_NAME
= "Server logger";Logger logger;ServerLogger() throws IOException
{(DEFAULT_NAME, DEFAULT_LOG_NAME);
}ServerLogger(String name) throws
IOException {(name, DEFAULT_LOG_NAME);
}ServerLogger(String name, String
filename) throws IOException {(name, filename);
}void init(String name, String
filename) throws IOException {fh = new FileHandler(filename);.setFormatter(new
HTMLFormatter());= Logger.getLogger(name);.addHandler(fh);
}void log(Level level, String msg)
{.log(level, msg);
}void log(Level level, String msg,
Throwable ex) {.log(level, msg, ex);
}
}com.gmail.dosofredriver.ajax.serviceserver.util.parser;java.util.Set;
/**
* Date: 07.03.13
* Time: 21:27
*
* @author DoSOfRR
*/class MethodStruct {Class []
argsTypes;String methodName;Set params;MethodStruct(String methodName, Set
params, Class [] argsTypes) {.methodName = methodName;.argsTypes =
argsTypes;.params = params;
}
}com.gmail.dosofredriver.ajax.serviceserver.util.parser;com.gmail.dosofredriver.ajax.serviceserver.util.collections.DefaultOrderComparator;org.json.simple.JSONArray;org.json.simple.JSONObject;org.json.simple.parser.JSONParser;java.util.*;
/**
* Date: 29.03.13
* Time: 3:22
*
* @author DoSOfRR
*/class Parser {static final String
KEY_METHODNAME = "methodName";static final String KEY_PARAMS =
"params";static MethodStruct parseRequest(String query) throws
Exception {<String, String> strParams = new TreeMap(new
DefaultOrderComparator());parser = new JSONParser();methodName;params;jsonObject
= (JSONObject)parser.parse(query);
//get method name from request=
(String) jsonObject.get(KEY_METHODNAME);
//get params from requestja =
(JSONArray) jsonObject.get(KEY_PARAMS);(Object param : ja) {.put(
(String) ((JSONObject) param).get("type"),
(String) ((JSONObject)
param).get("value")
);
}
//get classes from strings[] classes
= getClasses(strParams.keySet());
//get parameters=
getInstances(getMap(classes, strParams.values()));new MethodStruct(methodName,
params, classes);
}static Class []
getClasses(Set<String> classNames) throws ClassNotFoundException {[]
result = new Class[classNames.size()];i=0;(String name : classNames) {(name)
{"int" : result[i] = int.class; break;"long" : result[i] =
long.class; break;"boolean" : result[i] = boolean.class;break;:
result[i] = Class.forName(name);
}++;
}result;
}static Set
getInstances(Map<Class, String> args) throws Exception {result = new
TreeSet(new DefaultOrderComparator());(Map.Entry<Class, String> entry :
args.entrySet()) {(entry.getKey().toString()) {"boolean" :
result.add(Boolean.parseBoolean(entry.getValue())); break;"long" :
result.add(Long.parseLong(entry.getValue())); break;"int" :
result.add(Integer.parseInt(entry.getValue())); break;: result.add(getInstance(entry.getKey(),
entry.getValue()));
}
}result;
}static<T> T
getInstance(Class<T> tClass, String value) throws Exception
{(T)tClass.getConstructor(String.class).newInstance(value);
}static Map<Class, String>
getMap(Class [] classes, Collection<String> values) {<Class,
String> result = new TreeMap(new DefaultOrderComparator());i = 0;(String
value : values) {.put(classes[i], value);++;
}result;
}
}com.gmail.dosofredriver.ajax.serviceserver.util.view;
/**
* Date: 07.03.13
* Time: 22:32
*
* @author DoSOfRR
*/enum Commands {_Server,
Stop_Server, Restart_Server, SwitchOFF_Server, Deploy, Undeploy, Help,
Undefined, Exit
}com.gmail.dosofredriver.ajax.serviceserver.util.view;sun.reflect.generics.reflectiveObjects.NotImplementedException;java.io.IOException;java.io.OutputStream;
/**
* Date: 07.03.13
* Time: 22:45
*
* @author DoSOfRR
*/class ConsoleView implements
ViewInterface {OutputStream os;
/*
* Creates an console view.
*
* @param os
* Specifies output stream that will
be used to print messages.
*/ConsoleView(OutputStream os) {.os
= os;
}ConsoleView() {
//System.out as default output
stream..os = System.out;
}
@Overridevoid showDefault() throws
IOException {.write("Welcome to server administration
panel.\n".getBytes());.write("\nType \"-help\" to print
help \n".getBytes());
}
@Overridevoid showHelp() throws
IOException {.write("\nType \"-start\" to start
server.".getBytes());.write("\nType \"-stop\" to stop
server.".getBytes());.write("\nType \"-restart\" to restart
server.".getBytes());.write("\nType \"-help\" to get
help.".getBytes());
}
@Overridevoid showMessage(String
message) throws IOException {.write(message.getBytes());
}
@Overridevoid showAuthorize() throws
IOException {new NotImplementedException();
}
@OverrideCommands readMessage(byte[]
message) throws IOException {strmsg = new String(message);(strmsg)
{"-start" : return Commands.Start_Server;"-stop" : return
Commands.Stop_Server;"-help" : return
Commands.Help;"-restart" : return Commands.Restart_Server;: return
Commands.Undefined;
}
}
}com.gmail.dosofredriver.ajax.serviceserver.util.view;java.io.IOException;java.util.concurrent.BlockingQueue;java.util.concurrent.LinkedBlockingQueue;
/**
* Date: 07.03.13
* Time: 21:47
*
* @author DoSOfRR
*/
/*
* This interface realizes view for
admin panel. With that interface you can specify
* your view without changing
<code>Commander</code> controller.
*/interface ViewInterface
{<Commands> messages = new LinkedBlockingQueue<>();
/*
* This method is used to show
initial interface and/or message.
* Here you can write some tips for
users, or send HTML form, for example.
*/void showDefault() throws
IOException;
/*
* Show help, that can describe
commands, params etc.
*/void showHelp() throws
IOException;
/*
* Show some message that server send
to user.
*/void showMessage(String message) throws
IOException;
/*
* Show authorize form/message.
*/void showAuthorize() throws
IOException;
/*
* This method will invoked when an
message will arrived.
* Method should parseRequest
incoming <code>message</code> and
* return result as
<code>Commands</code> enum.
*/Commands readMessage(byte []
message) throws IOException;
}