Дипломная работа: Оценка возможностей применения инструментов статического анализа в учебном процессе для проверки решений задач по программированию

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

ID_PRB - идентификатор задачи, на которую прислано решение;

ID_CMP - идентификатор компилятора, используемого для компиляции донного решения;

ID_RSL - идентификатор результата проверки решения;

TEST_NO - в случае неверного решения, указывается номер теста на котором произошла ошибка;

TIME_WORK - максимальное (на один тест) время работы решения;

MEM_USE - максимальное (на один тест) использование решением оперативной памяти.

Результаты статического анализа будут сохранены в отдельную таблицу, структура которой в соответствии с JSON-структурой будет иметь следующий вид:

Таблица SOLUTION_ISSUES - ошибки, обнаруженные статическим анализатором. Атрибуты:

ISSUE_ID-идентификатор ошибки,

ID_STAT-идентификатор решения,

START_LINE-строка начала фрагмента кода с ошибкой,

START_COL-столбец начала фрагмента кода с ошибкой,

END_LINE-строка конца фрагмента кода с ошибкой,

END_COL-столбец конца фрагмента кода с ошибкой,

MESSAGE-сообщение об ошибке,

ID_BEAR-идентификатор модуля, обнаружившего ошибку,

SEVERITY-серьезность ошибки.

Также необходимо ввести в БД сущность проверяющего модуля coala:

Таблица BEAR - проверяющие модули. Атрибуты:

ID_BEAR-идентификатор модуля

NAME-название модуля

И таблицу-связку между компиляторами и проверяющими модулями:

Таблица COMPIL_BEAR - связка проверяющих модулей и компиляторов. Атрибуты:

ID_BEAR-Идентификатор проверяющего модуля,

ID_CMP-Идентификатор компилятора,

ENABLED-признак того, что проверка решений данным модулем включена для компилятора,

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

Часть схемы БД, которую затронули изменения, показана на рисунке 8.

Рисунок 8 - Измененная структура БД

2.7 Проектирование алгоритмов

Алгоритм обработки сообщения об окончании компиляции и проверки корректности вывода программы изображен на рисунке 9.

Рисунок 9 - Алгоритм обработки слушателем сообщения об окончании основной проверки решения

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

К окружению, в котором будет функционировать система, по результатам проектирования предъявлены требования на наличие следующего ПО:

JDK 1.8

Python 3.7.3

Erlang/OTP 22.0

RabbitMQ 3.7.15

3. Разработка

3.1 Выбор инструментальных средств разработки

Разработка приложения статического анализа будет выполняться в интегрированной среде разработки IntelliJIDEA 2019.1. Для управления зависимостями в проекте применено приложение Gradle.Для доработки приложения проверки решений main_mod будет использована интегрированная среда разработки MicrosoftVisualStudio 2019 с набором инструментов MicrosoftVisualC++ 2013.Для работы с СУБД Firebird, исполнения SQL-скриптов будет использована утилита IBExpert 2011.

3.2 Разработка структуры БД

В соответствии с проектом необходимо создать 3 таблицы, задав соответствующие ограничения на их столбцы:

Таблица проверяющих модулей

CREATETABLEBEAR (

ID_BEAR INTEGER NOT NULL,

NAME VARCHAR(50) NOT NULL

);

Таблица-связка проверяющих модулей с компиляторами

CREATETABLE COMPIL_BEAR (

ID_BEAR INTEGER NOT NULL,

ID_CMP INTEGER NOT NULL,

ENABLED CHAR(1) DEFAULT 'y' NOT NULL,

SHOWED CHAR(1) DEFAULT 'y' NOT NULL

);

Таблица найденных ошибок

CREATE TABLE SOLUTION_ISSUE (

ISSUE_ID INTEGER NOT NULL,

ID_STAT INTEGER NOT NULL,

START_LINE INTEGER,

START_COL INTEGER,

END_LINE INTEGER,

END_COL INTEGER,

MESSAGE VARCHAR(1000) NOT NULL,

ID_BEAR INTEGER NOT NULL,

SEVERITY INTEGER NOT NULL

);

Необходимо задать первичные и внешние ключи для таблиц:

ALTER TABLE BEAR ADD PRIMARY KEY (ID_BEAR);

ALTER TABLE COMPIL_BEAR ADD PRIMARY KEY (ID_BEAR, ID_CMP);

ALTER TABLE COMPIL_BEAR ADD FOREIGN KEY (ID_BEAR) REFERENCES BEAR (ID_BEAR);

ALTER TABLE COMPIL_BEAR ADD FOREIGN KEY (ID_CMP) REFERENCES COMPIL (ID_CMP);

ALTER TABLE SOLUTION_ISSUE ADD PRIMARY KEY (ISSUE_ID);

ALTER TABLE SOLUTION_ISSUE ADD FOREIGN KEY (ID_STAT) REFERENCES STATUS (ID_STAT);

ALTER TABLE SOLUTION_ISSUE ADD FOREIGN KEY (ID_BEAR) REFERENCES BEAR (ID_BEAR);

Также будут созданы генераторы идентификаторов для таблиц BEAR и SOLUTION_ISSUE и триггеры на вставку в эти таблицы, использующие генераторы. Полный листинг SQL-скриптов приведен в приложении 1.

3.3 Настройка AMQP-брокера

В качестве AMQP-брокера ранее был выбран RabbitMQ.Необходимо установить дистрибутив Erlang/OTP и затем RabbitMQ.На брокере нужно создать две очереди:

1. accepted_solutions - главная очередь, которая будет использоваться для обмена сообщениями между приложением main_mod и приложением статического анализа.

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

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

3.4 Доработка приложения main_mod.exe

Сборка библиотеки SimpleAmqpClient

Необходимым условием для сборки SimpleAmqpClient является наличие скомпилированных библиотек rabbitmq-cи boost. Поэтому сперва нужно собрать их и затем саму библиотеку SimpleAmqpClient.

Чтение конфигурации

Конфигурация приложения находится в файле master.cfg, откуда читается приложением в класс TConfig. В эту конфигурацию необходимо вынести настройки подключения к AMQP-брокеру. Для этого в класс TConfig добавляется структура TMessaging:

structTMessaging {

char* host;

char* port;

char* username;

char* password;

};

Отправка уведомлений по AMQP

При старте приложения устанавливается подключение к AMQP-брокеру вызовом следующей функции:

mqConnection = AmqpClient::Channel::Create(master_cfg->Messaging->host, atoi(master_cfg->Messaging->port), master_cfg->Messaging->username, master_cfg->Messaging->password);

Функция WhileTestSolve дорабатывается таким образом, что после проверки решения в очередь accepted_solutions отправляется сообщение с идентификатором решения:

string messageBody = "id_stat=" + to_string(elm.id_stat);

AmqpClient::BasicMessage::ptr_t message = AmqpClient::BasicMessage::Create(messageBody);

message->ContentType("text/plain");

mqConnection->BasicPublish("", "accepted_solutions", message);

3.5 Настройка приложения coala

coala предлагает несколько способов установки. Наиболее удобно развернуть coala в изолированной среде pipenv. Пререквизитами для этого является наличие установленного в системе Python.

В специально созданной директории необходимо выполнить команды pip3 install pipenv и pipenv install coala-bears. После этого можно приступать к работе с coala.Запуск командной строки в изолированной среде выполняется командой pipenv shell, после чего становятся доступны команды для взаимодействия с coala. В дальнейшем это будет использовано для запуска coala из Java-приложения.

3.6 Реализация приложения статического анализа

С учетом необходимых зависимостей от библиотек, листинг конфигурации сборки build.gradle приведен в приложении 2.

1. Точкой входа в приложение SpringBoot служит класс Application:

@SpringBootApplication

@EnableRabbit

@EnableJpaRepositories

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

Аннотации @SpringBootApplication, @EnableRabbit, @EnableJpaRepositories включают конфигурацию контекста Spring, автосканирование пакетов на Spring-компоненты, инициализацию AMQP-клиента для RabbitMQ и инициализацию JPA.

2. Разработка слоя доступа к данным

Для доступа к данным будет использована спецификация JPA (JavaPersistenceAPI). Она реализует концепцию ORM (объектно-реляционное отображение).

При помощи IntelliJIDEA можно сгенерировать классы сущностей JPA по имеющейся схеме БД. Пример такого класса для таблицы SOLUTION_ISSUES приведен в приложении 3.

Для удобной манипуляции данными в JPA можно задействовать библиотеку SpringData, тогда классы репозиториев будут выглядеть следующим образом:

Репозиторий сущности COMPIL.

public interface CompilRepository extends CrudRepository<CompilEntity, Short> {

}

Репозиторий сущности STATUS.

public interface StatusRepository extends CrudRepository<StatusEntity, Integer> {

}

Репозиторий сущности COMPIL_BEAR. В нем определены два дополнительных метода: для включения/отключения проверки модулем coala по компилятору и для включения/отключения отображения пользователю ошибок, обнаруженных конкретным модулем coala по компилятору.

public interface CompilBearRepository extends CrudRepository<CompilBearEntity, Short> {

@Modifying

@Query("update CompilBearEntity cb set cb.enabled = ?1 where cb.compilByIdCmp.idCmp = ?2 and cb.bearByIdBear.idBear = ?3")

int setEnabled(boolean enabled, short compilerId, int bearId);

@Modifying

@Query("update CompilBearEntity cb set cb.showed = ?1 where cb.compilByIdCmp.idCmp = ?2 and cb.bearByIdBear.idBear = ?3")

int setShowed(boolean showed, short compilerId, int bearId);

}

Эти интерфейсы наследуют методы для выполнения CRUD-операций из интерфейса CrudRepository.

3. Сервис проверки решения

Для обработки сообщений от AMQP необходимо создать новый компонент Spring, в котором должен быть метод помеченный аннотацией @RabbitListener(queues = "accepted_solutions"). Единственный параметр метода, строка content, является телом AMQP-сообщения.

Необходимо извлечь из тела параметр id_stat и получить по нему решение с помощью метода репозитория StatusRepository.findById(). Дальнейший алгоритм соответствует блок-схеме, приведенной в разделе 2.7. Отдельно рассмотреть стоит только взаимодействие с приложением coala в классе Analyzer.

Полный текст класса CheckingCompletionListener приведен в приложении 4

Ввод исходного текста и получение результатов в coala осуществляется через промежуточные файлы. Поэтому в методе Analyzer.analyze() в первую очередь генерируются случайные названия файлов для исключения конфликтов при конкурентном анализе нескольких решений:

String uuid = UUID.randomUUID().toString();

File in = new File(coalaPath + "\\" + uuid + ".in");

File out = new File(coalaPath + "\\" + uuid + ".out");

После этого исходный текст решения записывается в файл in:

FileUtils.writeStringToFile(in, source, StandardCharsets.UTF_8);

Далее следует непосредственно вызов coala в изолированной среде pipenv:

CommandLine cmdLine = CommandLine.parse("cmd /c cd " + coalaPath + " && echo coala -I --no-autoapply-warn --json" +

" --bears=" + String.join(",", bears) +

" --files=" + in.getName() +

" -o=" + out.getName() +

" | pipenv shell");

DefaultExecutor executor = new DefaultExecutor();

String json;

try {

executor.execute(cmdLine);

} catch (IOException e) {

e.printStackTrace();

}

По завершении результаты анализа считываются из файла out, файлы in и out удаляются и результат парсится из JSON-строки в Java-объекты с помощью библиотеки FasterXMLJackson:

try (FileInputStream fileInputStream = new FileInputStream(out)) {

json = IOUtils.toString(fileInputStream);

} catch (IOException e) {

throw new RuntimeException(e);

}

in.delete();

out.delete();

return parseJson(json);

4. REST-контроллеры

Будут созданы следующие REST-сервисы:

AdminController

GET /admin/bears - получение списка компиляторов в связке с проверяющими модулями и статусов активации сканирования и активации отображения пользователю

POST /admin/analysis-state - включение/отключение проверки модулем coala по компилятору

POST /admin/showing-state - включение/отключение отображения пользователю ошибок, обнаруженных конкретным модулем coala по компилятору

UserController

GET /issues получение списка ошибок по идентификатору решения

AuthController

GET /auth сервис, не несущий предметной пользы. Нужен только для аутентификации пользователя.

Полные исходные тексты классов контроллеров приведены в приложении 5.

5. Аутентификация в приложении

Аутентификация в приложении реализована с помощью библиотеки SpringSecurity. В приложение введены две роли: USER и ADMIN, соответствующие существующей ролевой модели дистанционного практикума. Роли ADMIN доступны все сервисы, включая сервисы соответствующие паттерну /admin/**. Роли USER доступны сервисы за исключением сервисов /admin/**.

Конфигурация безопасности выглядит следующим образом:

@Override

protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()

.antMatchers("/admin/**").hasAuthority("ADMIN")

.antMatchers("/**").hasAnyAuthority("USER", "ADMIN")

.and().httpBasic()

.and().csrf().disable();

}

Полный текст конфигурации безопасности, включающий механизм проверки логина и пароля пользователя и получения роли пользователя из БД приведен в приложении 6. Конфигурация приложения определяется в файле application.properties. Перечислим лишь основные параметры для подключения к БД, AMQP-брокеру и путь к директории с coala:

spring.rabbitmq.host=localhost

spring.rabbitmq.port=5672

spring.rabbitmq.username=guest

spring.rabbitmq.password=guest

spring.datasource.url=jdbc:firebirdsql://localhost/c:\\acm\\db\\acm.gdb

spring.datasource.username=sysdba

spring.datasource.password=masterkey

coala.path=C:\\coala

6. Сборка и запуск приложения

Приложение собирается командой gradlebuildJar. Собранный JAR создается в директории build/libs. Для подключения внешнего файла конфигурации достаточно расположить рядом с JAR файл application.properties. Запуск приложения осуществляется командой java -jarsas-1.0-SNAPSHOT.jar. При этом в переменной окружения PATH должна быть добавлена директория JDK 1.8.

3.7 Настройка ApacheHTTPServer

Вся настройка HTTP-сервера заключается в том, что необходимо добавить директивы для проксирования запросов по контексту /sas/ в приложение статического анализа:

ProxyPass /sas/ http://localhost:8081/