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

Анализ информационной системы "Бурятия.INFO". Построение функциональной модели "Как надо", диаграммы прецедентов, диаграммы последовательности действий, диаграммы классов. Разработка программного приложения в интегрированной среде Intellij IDEA.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 13.04.2014
Размер файла 1,3 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Дипломный проект

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

АННОТАЦИЯ

информационный программный приложение

Данная выпускная квалификационная работа посвящена вопросам разработки сервера приложений для ИП «Баяртуев Д.Б.».

В проекте были использованы известные в настоящее время технологии проектирования и средства разработки приложений, а именно: интегрированная среда разработки Intellij IDEA, средства проектирования IBM Rational Rose и BPWin.

В рамках проекта выполнены анализ предметной области, построена функциональная модель «Как надо», диаграмма прецедентов, диаграмма последовательности действий, диаграмма классов, разработано программное приложение.

Пояснительная записка содержит все необходимые разделы и части.

ВВЕДЕНИЕ

В настоящее время активно растёт сложность разработки и сопровождения информационных систем. Со временем могут появиться потребности в функционале, который не был предусмотрен первоначальной реализацией информационной системы. Кроме того, необходимый функционал не всегда возможно реализовать средствами одного языка программирования.

Выделение нового уровня в архитектуре, коим является сервер приложений, решает выше описанные проблемы. Внедрение сервера приложения позволяет существенно повысить функциональность и производительность готовой информационной системы, позволяя избежать изменений последней.

Разрабатываемый в данной работе сервер приложений предназначен для ИП «Баяртуев Д.Б.». В результате работы ИП «Баяртуев Д.Б.» получит универсальное средство, позволяющее управлять бизнес-логикой, которая может быть реализована и дополнена новым функционалом путём написания модулей-приложений.

Целью дипломного проекта является повышение эффективности и функциональности готовой информационной системы.

Для достижения указанной цели в соответствии объектом исследования поставлены следующие задачи:

1) изучение и анализ предметной области;

2) разработка функциональной модели «Как надо»;

3) проектирование сервера приложения:

- разработка диаграммы прецедентов;

- разработка диаграммы последовательности действий

- разработка диаграммы классов.

4) реализация сервера приложения:

- разработка программных модулей системы;

- тестирование сервера приложений.

1. АНАЛИЗ ТРЕБОВАНИЙ

1.1 Описание предметной области задачи

Информационная система «Бурятия.INFO» представляет собой сайт справочник компаний города Улан-Удэ. Пользователь сайта обладает возможностью создать страницу для своей компании, на который другие пользователи могут оставлять отзывы и комментарии.

Проект «Бурятия.INFO» рассчитан на широкую аудиторию, и предназначен в первую очередь для клиентов компаний, отзывы о которых размещаются на сайте. «Бурятия.INFO» это саморегулирующееся сообщество, где каждый пользователь может определённым образом повлиять на рейтинг компаний, других пользователей, вступить в обсуждение либо дискуссию с пользователями сайта.

Функционал сайта постоянно расширяется, что позволяет привлекать в сообщество новых людей, в тоже время, поддерживая интерес у “завсегдатаев сайта”. В следствии постоянно растущей динамики изменений понадобилось универсальное средство, способное решать большинство задач, связанных с описанным выше расширением функционала. В результате, было принято решение о выделении дополнительного архитектурного уровня - сервера приложений, способного обеспечить эффективную и удобную схему модулей-приложений.

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

Сам сайт «Бурятия.INFO» написан на языке программирования PHP. В качестве веб-сервера используется Apache. Так же, на стороне клиента используется javascript библиотека jQuery, представляющая удобные средства взаимодействия с клиентом-браузером.

После внедрения сервера приложений в информационную систему «Бурятия.INFO» заказчик получить гибкое, эффективное средство, которое позволит без изменений в архитектуре и исходном коде приложения расширять функционал информационной системы путём построения дополнительных модулей.

1.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. ПРОЕКТИРОВАНИЕ СИСТЕМЫ

2.1 Проектирование диаграммы прецедентов

В рамках дипломного проектирования разработаны диаграмма классов, диаграмма прецедентов и диаграмма последовательности действий. При разработке диаграмм было использовано Case-средство IBM Rational Rose.

Диаграмма прецедентов представлена на рисунке 2.1

Рисунок 2.1 - Диаграмма прецедентов

На диаграмме представлено три актёра:

Администратор - отвечает за настройку сервера, отдаёт команды на запуск и остановку последнего. Связанные процессы: “Настроить сервер”, “Запустить сервер приложений” и “Остановить сервер”.

Виртуальная машина является посредником между Администратором и сервером приложений. После обращения администратора к процессам “Запустить сервер приложений” и “Остановить сервер” контроль над работой сервера передаётся виртуальной машине. Она, в свою очередь, исполняет приложение в собственном контексте.

Сервер приложений - актёр, который занимается обработкой поступающих на сервер запросов. Связанные процессы: “Обработать запрос” и “Развернуть приложение”.

На выше описанной диаграмме представлены все основные актёры и процессы, участвующие в работе разрабатываемой информационной системе «Сервер приложений». Далее будет рассмотрена диаграмма последовательности действий, изображённая на рисунке 2.2.

2.2 Проектирование диаграммы последовательности действий

Рисунок 2.2 - Диаграмма последовательности действий

Диаграмма последовательности действий призвана наглядно отобразить набор процессов, их последовательность и взаимодействие. Ниже будут описаны все объекты изображённые на рисунке 2.2.

Обработчик соединений - объект, который отвечает за установку соединений. Также занимается фильтрацией и закрытием соединений. Тесно взаимодействует с системой ввода\вывода.

Система ввода\вывода занимается чтением и записью данных, используя полученное соединение. После чтения передаёт данные в специальный обработчик.

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

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

2.3 Проектирование диаграммы классов

Рисунок 2.3 - Диаграмма классов

На диаграмме классов представлены классы, используемые приложением, и их взаимодействие. Представленные на диаграмме классы:

Commander - класс, осуществляющий управление сервером на уровне приложения.

ViewInterface - интерфейс, который определяет поведение графических оболочек.

ConsoleView - конкретная реализация интерфейса VIewInterface, которая представляет графический интерфейс пользователя в виде стандартной консоли.

Commands - перечисление, представляющее набор команд, распознаваемых сервером.

TCPServer - TCP сервер, занимающийся обработкой соединений.

ServerPipelineFactory - фабрика, определяющая модель обработки соединений.

Классы пакета handlers представляют этапы обработки соединения.

Session - объект сессии, сформированный на уровне транспортного протокола. Служит для хранения соединения и полученных данных.

SessionController - контейнер, который занимается хранением объектов класса Session.

Worker - рабочий класс, определяющий цикл обработки запросов. Занимается выборкой сессий из SessionController, и передачей их на дальнейшую обработку.

Service - класс, определяющий логику обработки данных бизнес процессами.

Parser - класс обработки данных, занимается извлечением и систематизацией данных.

MethodStruct - служебная структура, хранящая обработанные данные.

Invoker - класс, занимающийся вызовом приложений, размещённых на сервере.

InvokerCache - внутренний кэш. Хранит служебные данные, необходимые для вызова приложений.

3. РЕАЛИЗАЦИЯ ПРОЕКТА

3.1 Выбор средств разработки

Для разработки информационной системы использован язык Java и визуальная среда разработки IntelliJ IDEA.

Java -- объектно-ориентированный язык программирования, разработанный компанией 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 позволяет достаточно быстро развернуть многопоточное серверное приложение, а так же предоставляет удобные средства для работы с соединениями и их обработки.

3.2 Архитектура программы

В архитектурном решении программы использовались основные принципы построения сервера приложений. Введем понятие «Сервер приложений».

Сервер приложений (англ. application server) -- это программная платформа (software framework), предназначенная для эффективного исполнения процедур (программ, механических операций, скриптов), которые поддерживают построение приложений. Сервер приложений действует как набор компонентов, доступных разработчику программного обеспечения через API (Интерфейс прикладного программирования), который определен самой платформой.

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

Рисунок 3.1 - Архитектура программы

Клиент - браузер, который формирует запросы к серверу приложений.

Приложение - программная единица, исполняемая в контексте сервера приложений и реализующая бизнес-логику.

Управление данными - часть сервера приложений, которая взаимодействует с хранилищами, управляет процессами добавлением, изменением и удалением данных.

База данных - предметно-ориентированная информационная база данных.

Детальная схема, на которой изображено более подробное представление архитектуры сервера приложений, описана ниже (рисунок 3.2).

Рисунок 3.2 - Детальная схема

Транспортный уровень - включает обработку соединений и чтение данных. Обработка соединений происходить под управлением фреймворка Netty, которые использует специальные фильтры. После успешной установки соединений происходит чтение данных.

Обработка данных - включает извлечение служебных данных, таких как имя пользователя и данные о параметрах приложений.

Инициализация приложения - включает поиск приложения и инициализацию параметров. Поиск приложения сначала обращается к внутри программному кэшу. В случае если приложение не было найдено в кэше, производится поиск по пространству имён приложения. После производится инициализация параметров, которая включает в себя создание экземпляров на основе данных, переданных в запросе.

Запуск приложения - включает менеджер ресурсов, который выделяет ресурсы на выполнение приложения. После результат выполнения приложения отправляется клиенту в качестве ответа. Менеджер ресурсов занимается выделением и освобождением ресурсов для приложений, частично управляет контекстом исполнения.

3.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. ДОКУМЕНТИРОВАНИЕ

4.1 Руководство пользователя

4.1.1 Характеристика и назначение программы

Программа представляет собой консольное Java-приложение. Для работы с данной программой пользователь должен иметь навыки работы с операционными системами Windows XP.

4.1.2 Требования к программе

Минимальный состав средств вычислительной техники и программного обеспечения для установки клиентского приложения:

- процессор Pentium и выше;

- оперативная память не менее 128 MB;

- дисковое пространство для установки клиентского приложения - 10 МB;

- виртуальная машина Java;

- операционная система с поддержкой Java SE 1.5.

Эти величины в действительности являются только минимумом. Чем выше быстродействие процессора и больше объем памяти, тем выше производительность компьютера, а, следовательно, и приложения. Также необходимо учесть, что для выполнения некоторых приложений может понадобиться дополнительное программное обеспечение, например, система управления базами данных.

4.1.3 Программные команды

Для управления работой программы используются специальные управляющие команды. Ниже представлено их описание.

-start - производит запуск сервера приложений;

-stop - производит остановку сервера приложений;

-restart - производит перезапуск сервера приложений;

-help - вызов справки.

4.1.4 Параметры запуска

Параметры запуска используются для более эффективной инициализации приложения. Ниже представлены реализованные параметры запуска.

configpath:<value> - указывает системный путь к конфигурационному файлу.

autostart - указывает приложению о необходимости запуска сервера приложений непосредственно после запуска.

4.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 - определяет путь к чёрному списку, если используются нестандартные пути;

4.1.6 Лог-файл

Лог-файл - специальный файл, который облегчает работу администратора с сервером приложений. В лог-файл записываются служебная информация, сведения об ошибках времени выполнения и т.д. Лог-файл выполнен в формате HTML. Всего существует три уровня сообщений: INFO, WARNING, SEVERE.

INFO - такой меткой помечается служебная информация, например, сообщение а запуске приложения, сетевой порт.

WARNING - эта метка указывает на некритичные ошибки выполнения. Выделяется серым цветом.

SEVERE - указывает на критические ошибки выполнения, после которых, зачастую, нормальное функционирование сервера невозможно. Часто помогает в отладке. Выделяется красным цветом.

4.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;

import com.gmail.dosofredriver.ajax.serviceserver.server.TCPServer;

import com.gmail.dosofredriver.ajax.serviceserver.service.worker.Worker;

import com.gmail.dosofredriver.ajax.serviceserver.util.configure.Configurator;

import com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;

import com.gmail.dosofredriver.ajax.serviceserver.util.view.ConsoleView;

import com.gmail.dosofredriver.ajax.serviceserver.util.view.ViewInterface;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.logging.Level;

/**

* Date: 06.03.13

* Time: 22:54

*

* @author DoSOfRR

*/

public class Commander {

public static final String DEFAULT_CONFIG_PATH = "config/config.txt";

private String configPath = DEFAULT_CONFIG_PATH;

private ViewInterface view;

private ServerLogger logger;

private TCPServer server;

private Thread serverThread;

private Thread workerThread;

private Worker worker;

private boolean autoStart = false;

private boolean isLogged = false;

public Commander(ViewInterface view, String ... args) {

this.view = view;

init(args);

}

private void init(String ... args) {

try {

parseArgs(args);

Configurator config = new Configurator(configPath);

logger = config.getConfiguredLogger();

server = config.getConfiguredServer();

worker = config.getConfiguredWorker();

worker.setLogger(logger);

server.setLogger(logger);

server.setFilter(config.getConfiguredFilter());

if (logger != null) {

isLogged = true;

server.setLogger(logger);

}

if (autoStart) {

this.startServer();

}

} catch (Exception e) {

System.err.println("An error occupied while initializing server: \n" + e);

}

}

private void parseArgs(String ... args) {

for (String arg : args) {

String value = null;

String type;

if (arg.contains(":")) {

type = arg.substring(0, arg.indexOf(':'));

value = arg.substring(arg.indexOf(':')+1, arg.length());

} else {

type = arg;

}

switch (type) {

case "configpath" : configPath = "value"; break;

case "autostart" : autoStart = true; break;

default: {

System.out.println("Option " + value + " is not supported!");

System.exit(0);

}

}

}

}

public void startServer() {

serverThread = new Thread(new Runnable() {

@Override

public void run() {

server.start();

}

});

workerThread = new Thread(new Runnable() {

@Override

public void run() {

try {

worker.start(); //todo ex

} catch (InterruptedException e) {

logger.log(Level.SEVERE, "Can not start worker!", e);

}

}

});

serverThread.setDaemon(true);

serverThread.start();

workerThread.setDaemon(true);

workerThread.start();

}

public void stopServer() {

try {

server.stop();

serverThread.interrupt();

worker.stop();

workerThread.interrupt();

} catch (InterruptedException e) {

logger.log(Level.WARNING, "An error occupied while stopping server", e);

}

}

public boolean deploy() {

return false;

}

/*

* This is a default program entry point.

*/

public static void main(String ... args) {

Commander commander = new Commander(new ConsoleView(), args);

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

boolean run = true;

try {

commander.view.showDefault();

} catch (IOException e) {

e.printStackTrace();

}

while (run) {

byte [] message;

try {

message = br.readLine().getBytes();

switch (commander.view.readMessage(message)) {

case Help : commander.view.showHelp(); break;

case Start_Server : commander.startServer(); break;

case Stop_Server : commander.stopServer(); break;

case Undefined : commander.view.showMessage("Undefined command."); break;

case Exit : run = false; break;

default : commander.view.showMessage("Not supported yet.");

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;

import com.gmail.dosofredriver.ajax.serviceserver.server.pipeline.ServerPipelineFactory;

import com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;

import org.jboss.netty.bootstrap.ServerBootstrap;

import org.jboss.netty.channel.Channel;

import org.jboss.netty.channel.ChannelFuture;

import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

import java.net.InetSocketAddress;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.logging.Level;

/**

* Date: 25.02.13

* Time: 23:47

*

* @author DoSOfRR

*/

public class TCPServer {

public static final String DEFAULT_IP_ADDRESS = "127.0.0.1";

public static final int DEFAULT_POOL_SIZE = 4;

public static final int DEFAULT_PORT = 777;

private ServerPipelineFactory serverPipeline;

private ServerBootstrap server;

private ServerLogger logger;

private Channel mainChannel;

private String address;

private boolean isStarted = false;

private boolean isLogged = false;

private int poolSize;

private int port;

public TCPServer() {

this(DEFAULT_PORT, DEFAULT_POOL_SIZE, DEFAULT_IP_ADDRESS);

}

public TCPServer(int port) {

this(port, DEFAULT_POOL_SIZE, DEFAULT_IP_ADDRESS);

}

public TCPServer(int port, int poolSize) {

this(port, poolSize, DEFAULT_IP_ADDRESS);

}

public TCPServer(int port, int poolSize, String address) {

this.port = port;

this.address = address;

this.poolSize = poolSize;

serverPipeline = new ServerPipelineFactory();

}

public void start() {

if (!isStarted) {

try {

ExecutorService bossExec = Executors.newFixedThreadPool(1);

ExecutorService workExec = Executors.newFixedThreadPool(poolSize);

server = new ServerBootstrap(new NioServerSocketChannelFactory(bossExec, workExec, poolSize));

server.setOption("backlog", 500); //todo config

server.setOption("connectTimeoutMillis", 10000);

server.setPipelineFactory(serverPipeline);

mainChannel = server.bind(new InetSocketAddress(address, port));

isStarted = true;

if (isLogged) {

logger.log(Level.INFO, "Server started on " + port + " port.");

}

System.out.println("Server started on " + port + " port.");

} catch (Exception e) {

if (isLogged) {

System.out.println("An error occupied while starting server. See log for more info.");

logger.log(Level.SEVERE, "An error occupied while starting server.", e);

} else {

System.out.println("An error occupied while starting server. \n" + e);

}

}

} else {

System.out.println("Server is already started!");

}

}

public void stop() {

if (isStarted) {

ChannelFuture future = mainChannel.close();

future.awaitUninterruptibly();

server.shutdown();

isStarted = false;

if (isLogged) {

logger.log(Level.INFO, "Server was manually stopped.");

}

System.out.println("Server stopped.");

} else {

System.out.println("Server is not started!");

}

}

public ServerLogger getLogger() {

return logger;

}

public void setLogger(ServerLogger logger) {

if (logger == null) {

throw new NullPointerException("Logger can not be null!");

}

this.logger = logger;

isLogged = true;

}

public void setFilter(ConnectionFilter filter) throws Exception {

serverPipeline.getPipeline().addFirst("Filter", filter);

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.session;

import org.jboss.netty.channel.Channel;

import java.nio.ByteBuffer;

/**

* Date: 02.03.13

* Time: 19:13

*

* @author DoSOfRR

*/

public class Session {

private ByteBuffer data;

private Channel channel;

public Session(ByteBuffer data, Channel channel) {

this.setChannel(channel);

this.setData(data);

}

public ByteBuffer getData() {

return data;

}

public void setData(ByteBuffer data) {

this.data = data;

}

public Channel getChannel() {

return channel;

}

public void setChannel(Channel channel) {

this.channel = channel;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.session;

import org.jboss.netty.channel.ChannelFuture;

import org.jboss.netty.channel.ChannelFutureListener;

import org.jboss.netty.channel.Channels;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingQueue;

/**

* Date: 27.02.13

* Time: 14:42

*

* @author DoSOfRR

*/

public class SessionController {

private BlockingQueue<Session> store;

private static SessionController ourInstance = new SessionController();

public static SessionController getInstance() {

return ourInstance;

}

private SessionController() {

store = new LinkedBlockingQueue<>();

}

public void putSession(Session session) throws InterruptedException {

store.put(session);

}

public void response(Session session) {

ChannelFuture future = Channels.write(session.getChannel(), session);

future.addListener(ChannelFutureListener.CLOSE);

}

public Session getSession() throws InterruptedException {

return store.take();

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.pipeline;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.DataReader;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.Decoder;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.Encoder;

import org.jboss.netty.channel.ChannelPipeline;

import org.jboss.netty.channel.ChannelPipelineFactory;

import org.jboss.netty.channel.Channels;

/**

* Date: 26.02.13

* Time: 23:26

*

* @author DoSOfRR

*/

public class ServerPipelineFactory implements ChannelPipelineFactory {

@Override

public ChannelPipeline getPipeline() throws Exception {

ConnectionFilter filter = new ConnectionFilter();

//todo config

ChannelPipeline result = Channels.pipeline(new Decoder(), new Encoder(), new DataReader());

return result;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.handlers;

import org.jboss.netty.channel.ChannelEvent;

import org.jboss.netty.channel.ChannelHandlerContext;

import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

import java.util.HashSet;

import java.util.Set;

/**

* Date: 26.02.13

* Time: 14:49

*

* @author DoSOfRR

*/

public class ConnectionFilter extends SimpleChannelUpstreamHandler {

public static final String DEFAULT_WHITELIST_PATH = "config/whitelist.txt";

public static final String DEFAULT_BLACKLIST_PATH = "config/blacklist.txt";

public static final int WHITELIST_ON = 0;

public static final int BLACKLIST_ON = 1;

public static final int WHITELIST_OFF = 3;

public static final int BLACKLIST_OFF = 4;

private final Set<String> whiteList = new HashSet<>();

private final Set<String> blackList = new HashSet<>();

private String whiteListPath;

private String blackListPath;

private boolean isWhiteListOn;

private boolean isBlackListOn;

public ConnectionFilter() {

isWhiteListOn = false;

isBlackListOn = false;

whiteListPath = DEFAULT_WHITELIST_PATH;

blackListPath = DEFAULT_BLACKLIST_PATH;

}

public void setOption(int list, String listPath) throws IllegalArgumentException, IOException {

switch (list) {

case BLACKLIST_ON: {

blackListPath = listPath;

isBlackListOn = true;

} break;

case WHITELIST_ON: {

whiteListPath = listPath;

isWhiteListOn = true;

} break;

default: throw new IllegalArgumentException();

}

loadList();

}

public void setOption(int list) throws IllegalArgumentException, IOException {

switch (list) {

case BLACKLIST_ON: isBlackListOn = true; break;

case WHITELIST_ON: isWhiteListOn = true; break;

case BLACKLIST_OFF: isBlackListOn = false; break;

case WHITELIST_OFF: isWhiteListOn = false; break;

default: throw new IllegalArgumentException();

}

loadList();

}

public boolean reloadLists() throws IOException {

loadList();

return true;

}

@Override

public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {

String addr;

addr = ctx.getChannel().getRemoteAddress().toString();

addr = addr.substring(1, addr.indexOf(':'));

if (isBlackListOn) {

if (blackList.contains(addr)) {

ctx.getChannel().close(); //rejects incoming connection

}

}

if (isWhiteListOn) {

if (!whiteList.contains(addr)) {

ctx.getChannel().close(); //rejects incoming connection

}

}

}

private void loadList() throws IOException {

BufferedReader br;

String line;

if (isBlackListOn) {

br = new BufferedReader(new FileReader(blackListPath));

while ((line = br.readLine()) != null) {

blackList.add(line);

}

}

if (isWhiteListOn) {

br = new BufferedReader(new FileReader(whiteListPath));

while ((line = br.readLine()) != null) {

whiteList.add(line);

}

}

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.handlers;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.SessionController;

import org.jboss.netty.channel.ChannelHandlerContext;

import org.jboss.netty.channel.ExceptionEvent;

import org.jboss.netty.channel.MessageEvent;

import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

/**

* Date: 26.02.13

* Time: 23:51

*

* @author DoSOfRR

*/

public class DataReader extends SimpleChannelUpstreamHandler {

@Override

public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {

Object message = e.getMessage();

if (message instanceof Session) {

SessionController.getInstance().putSession((Session) message);

}

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {

//todo log exception

System.err.println("Err from: " + e.getChannel().getRemoteAddress());

e.getChannel().close();

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.handlers;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;

import org.jboss.netty.buffer.ChannelBuffer;

import org.jboss.netty.channel.Channel;

import org.jboss.netty.channel.ChannelHandlerContext;

import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;

import java.nio.ByteBuffer;

/**

* Date: 27.02.13

* Time: 2:07

*

* @author DoSOfRR

*/

public class Decoder extends OneToOneDecoder {

private int length;

@Override

protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {

if (msg instanceof ChannelBuffer) {

ByteBuffer data = ByteBuffer.wrap(((ChannelBuffer) msg).array());

return new Session(data, channel);

}

return null;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.server.handlers;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;

import org.jboss.netty.buffer.ChannelBuffers;

import org.jboss.netty.channel.Channel;

import org.jboss.netty.channel.ChannelHandlerContext;

import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;

/**

* Date: 02.03.13

* Time: 19:06

*

* @author DoSOfRR

*/

public class Encoder extends OneToOneEncoder {

@Override

protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {

if (msg instanceof Session) {

return ChannelBuffers.wrappedBuffer(((Session) msg).getData());

} else {

return ChannelBuffers.EMPTY_BUFFER;

} //note the writer should manually close channel after the message walk through pipeline

}

}

package com.gmail.dosofredriver.ajax.serviceserver.service;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;

import com.gmail.dosofredriver.ajax.serviceserver.util.invoke.Invoker;

import com.gmail.dosofredriver.ajax.serviceserver.util.parser.Parser;

import java.nio.ByteBuffer;

/**

* Date: 07.03.13

* Time: 21:19

*

* @author DoSOfRR

*/

public class Service {

public static Session service(Session session) throws Exception {

String request = new String(session.getData().array()); //get AJAX request

Object result = Invoker.invoke(Parser.parseRequest(request)); //parse it, and call application

return new Session(ByteBuffer.wrap(result.toString().getBytes()), session.getChannel()); //return new Session

}

}

package com.gmail.dosofredriver.ajax.serviceserver.service.worker;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.Session;

import com.gmail.dosofredriver.ajax.serviceserver.server.session.SessionController;

import com.gmail.dosofredriver.ajax.serviceserver.service.Service;

import com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

import java.util.logging.Level;

/**

* Date: 06.03.13

* Time: 21:04

*

* @author DoSOfRR

*/

public class Worker {

public static final int DEFAULT_POOL_SIZE = 8;

private volatile boolean stopFlag = false;

private ExecutorService executor;

private ServerLogger logger;

private boolean isLogged = false;

public Worker() {

this(DEFAULT_POOL_SIZE);

}

public Worker(int pool_size) {

init(pool_size);

}

private void init(int pool_size) {

executor = Executors.newFixedThreadPool(pool_size);

}

public void start() throws InterruptedException {

if (isLogged) {

logger.log(Level.INFO, "Worker started.");

}

stopFlag = false;

while (!stopFlag) {

final Session session = SessionController.getInstance().getSession();

executor.execute(new Runnable() {

@Override

public void run() {

try { SessionController.getInstance().response(Service.service(session));

} catch (Exception e) {

if (isLogged) {

logger.log(Level.SEVERE, "An error occupied while parsing request!", e);

session.getChannel().close(); //note try to use AutoCloseable

}

}

}

});

}

}

public void stop() throws InterruptedException {

stopFlag = true;

executor.awaitTermination(10, TimeUnit.SECONDS); //note хуй знает почему таски работающие висят :\

if (isLogged) {

logger.log(Level.INFO, "Worker was manually stopped.");

}

}

public void setLogger(ServerLogger logger) {

if (logger == null) {

throw new NullPointerException("Logger can not be null!");

}

this.logger = logger;

isLogged = true;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.service.annotations;

/**

* This exception указывает for controller implementation error.

* Controller class must be annotated with <code>ServiceClass</code> annotation.

*/

public class IsNotAnnotatedException extends Throwable {

private String message;

public IsNotAnnotatedException() {

message = "Given class or method is not annotated!";

}

public IsNotAnnotatedException(Throwable ex) {

super(ex);

message = "Given class or method is not annotated!";

}

public IsNotAnnotatedException(String message) {

this.message = message;

}

public IsNotAnnotatedException(String message, Throwable ex) {

super(ex);

this.message = message;

}

}

package 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;

*/

import java.lang.annotation.*;

@Documented

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ServiceMethod {

}

package com.gmail.dosofredriver.ajax.serviceserver.util.collections;

import java.util.Comparator;

/**

* Date: 29.03.13

* Time: 21:51

*

* @author DoSOfRR

*/

public class DefaultOrderComparator implements Comparator {

@Override

public int compare(Object o1, Object o2) {

return 1;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.util.configure;

import com.gmail.dosofredriver.ajax.serviceserver.server.TCPServer;

import com.gmail.dosofredriver.ajax.serviceserver.server.handlers.ConnectionFilter;

import com.gmail.dosofredriver.ajax.serviceserver.service.worker.Worker;

import com.gmail.dosofredriver.ajax.serviceserver.util.logger.ServerLogger;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.StringTokenizer;

/**

* Date: 26.04.13

* Time: 2:14

*

* @author DoSOfRR

*/

public class Configurator {

private ConnectionFilter configuredFilter;

private ServerLogger configuredLogger;

private TCPServer configuredServer;

private Worker configuredWorker;

public Configurator(String configPath) throws IOException {

init(configPath);

}

private void init(String configPath) throws IOException {

String data = readFile(configPath);

if (data == null) {

setDefaults();

return;

}

parseConfig(data);

}

private void parseConfig(String data) throws IOException {

String whiteList_path = ConnectionFilter.DEFAULT_WHITELIST_PATH;

String blackList_path = ConnectionFilter.DEFAULT_BLACKLIST_PATH;

String server_ip = TCPServer.DEFAULT_IP_ADDRESS;

String log_name = ServerLogger.DEFAULT_LOG_NAME;

int server_pool_size= TCPServer.DEFAULT_POOL_SIZE;

int worker_pool_size= Worker.DEFAULT_POOL_SIZE;

int server_port = TCPServer.DEFAULT_PORT;

boolean blackListOn = false;

boolean whiteListOn = false;

StringTokenizer tokenizer = new StringTokenizer(data);

while (tokenizer.hasMoreTokens()) {

String line = tokenizer.nextToken();

String type = line.substring(0, line.indexOf('='));

String value= line.substring(line.indexOf('=')+1, line.length());

switch (type.toLowerCase()) {

case "server-pool-size" : server_pool_size = Integer.parseInt(value); break;

case "worker-pool-size" : worker_pool_size = Integer.parseInt(value); break;

case "server-port" : server_port = Integer.parseInt(value); break;

case "server-ip" : server_ip = value; break;

case "log-name" : log_name = value; break;

case "blacklist" : blackListOn = Boolean.parseBoolean(value); break;

case "whitelist" : whiteListOn = Boolean.parseBoolean(value); break;

case "whitelist-path" : whiteList_path = value; break;

case "blacklist-path" : blackList_path = value; break;

default: System.err.println("Unknown config option - " + value);

}

this.configuredWorker = new Worker(worker_pool_size);

this.configuredServer = new TCPServer(server_port, server_pool_size, server_ip);

this.configuredLogger = new ServerLogger(ServerLogger.DEFAULT_NAME, log_name);

this.configuredFilter = new ConnectionFilter();

//configure filter

if (blackListOn) {

this.configuredFilter.setOption(ConnectionFilter.BLACKLIST_ON, blackList_path);

}

if (whiteListOn) {

this.configuredFilter.setOption(ConnectionFilter.WHITELIST_ON, whiteList_path);

}

}

}

private String readFile(String configPath) throws IOException {

File file = new File(configPath);

FileInputStream fis;

byte [] buffer;

if (!file.exists()) {

return null;

}

fis = new FileInputStream(file);

buffer = new byte[fis.available()];

for (int b, count = 0; (b = fis.read()) != -1; count++) {

buffer[count] = (byte) b;

}

return new String(buffer);

}

private void setDefaults() throws IOException {

this.configuredFilter = new ConnectionFilter();

this.configuredLogger = new ServerLogger();

this.configuredServer = new TCPServer();

this.configuredWorker = new Worker();

}

public ConnectionFilter getConfiguredFilter() {

return configuredFilter;

}

public ServerLogger getConfiguredLogger() {

return configuredLogger;

}

public TCPServer getConfiguredServer() {

return configuredServer;

}

public Worker getConfiguredWorker() {

return configuredWorker;

}

}

package com.gmail.dosofredriver.ajax.serviceserver.util.invoke;

import java.lang.reflect.Method;

import java.util.concurrent.ConcurrentHashMap;

/**

* Date: 29.03.13

* Time: 1:48

*

* @author DoSOfRR

*/

public class InvokeCache {

private static InvokeCache ourInstance = new InvokeCache();

private ConcurrentHashMap<String, Class> cachedClasses = new ConcurrentHashMap();

private ConcurrentHashMap<String, Method> cachedMethods = new ConcurrentHashMap();

public static InvokeCache getInstance() {

return ourInstance;

}

private InvokeCache() {

}

public Method findMethod(String methodName) {

return cachedMethods.get(methodName);

}

public Class findClass(String className) {

return cachedClasses.get(className);

}

public boolean cacheMethod(Method method) {

if (findMethod(method.toString()) == null) {

cachedMethods.put(method.toString(), method);

return true;

} else {

return false;

}

}

public boolean cacheClass(Class clazz) {

if (findClass(clazz.getName()) == null) {

cachedClasses.put(clazz.getName(), clazz);

return true;

} else {

return false;

}

}

private void clearCache() {

cachedClasses.clear();

cachedMethods.clear();

}

}

package com.gmail.dosofredriver.ajax.serviceserver.util.invoke;

import com.gmail.dosofredriver.ajax.serviceserver.service.annotations.ServiceMethod;

import com.gmail.dosofredriver.ajax.serviceserver.util.parser.MethodStruct;

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

/**

* Date: 28.03.13

* Time: 2:11

*

* @author DoSOfRR

*/

public class Invoker {

private static IllegalArgumentException cachedException = new IllegalArgumentException(new NullPointerException("Method can not be null!"));

public static Object invoke(MethodStruct param) throws Exception { //todo check security fuckups

String methodName = param.methodName.substring(param.methodName.lastIndexOf(".")+1, param.methodName.length());

String className = param.methodName.substring(0, param.methodName.lastIndexOf("."));

Class clazz = getClass(className);

Method method = getMethod(methodName, clazz, param.argsTypes);

if (method == null)

throw cachedException;

//security check

if (!method.isAnnotationPresent(ServiceMethod.class)) {

throw new SecurityException("Method is not annotated with ServiceMethod!");

}

//use another invoke type if method is static

if (Modifier.isStatic(method.getModifiers())) {

return method.invoke(clazz.getClass(), param.params.toArray());

} else {

return method.invoke(clazz.newInstance(), param.params.toArray()); //todo create method to get class instance?

}

}

private static Method getMethod(String methodName, Class owner, Class [] params) throws NoSuchMethodException, ClassNotFoundException {

InvokeCache cache = InvokeCache.getInstance();

Method result;

if ((result = cache.findMethod(methodName)) != null) { //try to find method in cache

return result;

} else {

result = owner.getMethod(methodName, params);

return result;

}

}

private static Class getClass(String className) throws ClassNotFoundException {

InvokeCache cache = InvokeCache.getInstance();

Class result;

if ((result = cache.findClass(className)) != null) {

return result;

} else {

result = Class.forName(className);

cache.cacheClass(result);

return result;

}

}

}

package com.gmail.dosofredriver.ajax.serviceserver.util.logger;

import java.io.PrintWriter;

import java.io.StringWriter;

import java.util.Date;

import java.util.logging.Formatter;

import java.util.logging.Handler;

import java.util.logging.Level;

import java.util.logging.LogRecord;

/**

* @author Урванов Ф. В.

* Класс, преобразующий лог в формат HTML.

*

*/

class HTMLFormatter extends Formatter {

/**

* Return head of HTML file.

*/

@Override

public String getHead(Handler h)

{

/**

* Write title, meta data and table.

*/

return "<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.

*/

@Override

public String getTail(Handler h)

{

/**

* Write end of table and HTML file.

*/

return "</table></body></html>";

}

/**

* Format message to table string.

*/

@Override

public String format(LogRecord record)

{

StringBuilder result=new StringBuilder();

Date d = new Date();

Level level = record.getLevel();

/**

* Error will be highlighted with red color,

* warnings with grey,

* info messages with white.

*/

if (level==Level.SEVERE)

{

result.append("<tr bgColor=Tomato><td>");

}

else if (level==Level.WARNING)

{

result.append("<tr bgColor=GRAY><td>");

}

else

{

result.append("<tr bgColor=WHITE><td>");

}

result.append("\n");

result.append(d);

result.append("</td><td>");

result.append(record.getLevel().toString());

result.append("</td><td>");

result.append(record.getSourceClassName());

result.append("</td><td>");

result.append(record.getSourceMethodName());

result.append("</td><td>");

result.append(record.getMessage());

result.append("</td><td>")

Throwable thrown = record.getThrown();

if (thrown!=null)

{

// Если было передано исключение, то выводим полный

// стек вызовов.

result.append(record.getThrown().getMessage());

result.append("</td><td>");

StringWriter sw = new StringWriter();

PrintWriter pw = new PrintWriter(sw);

record.getThrown().printStackTrace(pw);

String stackTrace=sw.toString();

result.append(stackTrace);

result.append("</td>");

}

else

{

// Просто пустые ячейки.

result.append("</td><td>null");

result.append("</td>");

}

// Конец строки

result.append("</tr>\n");

return result.toString();

}

}

package com.gmail.dosofredriver.ajax.serviceserver.util.logger;


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.