Немного теории о проектах и VFS. Предыдущая часть тут.
Структура проекта
В IntelliJ IDEA проект инкапсулирует все исходные коды, библиотеки, сценарии сборки в едином организационном блоке. Абсолютно все действия в IDEA происходят в контексте проекта. Проект может содержать коллекции модулей и библиотек. В зависимости от логических или функциональных требований, можно создать одномодульный или многомодульный проект.
Модули
Модуль – это отдельная сущность функциональности, которая может быть запущена, протестирована и отлажена независимо.
Модули включают такие вещи как исходные коды, сценарии сборки, юнит-тесты, и т.д. Каждый модуль в проекте может использовать определенный SDK, либо наследовать SDK проекта. Модули могут зависеть от других модулей в проекте.
Библиотеки
Библиотека – это скомпилированный код в архиве (например, JAR-файл) от которого зависят модули.
IntelliJ IDEA Community Edition поддерживает три типа библиотек:
- библиотека модуля – видна только в данном модуле, информация о ней сохраняется в *.iml-файл;
- библиотека проекта – видна внутри всего проекта, информация о ней сохраняется в *.ipr-файл;
- глобальная библиотека – информация о ней сохраняется в файле applicationLibraries.xml, видимость которого распространяется на все проекты.
SDK
Каждый проект использует Software Development Kit (SDK). Для Java проектов существует специальный тип SDK, называемый JDK (Java Development Kit). SDK определяет какой API используется при сборке проекта. В многомодульном проекте, по-умолчанию, SDK наследуется всеми модулями, но также возможно определить отдельные SDK для соответствующих модулей.
Facet
Facet – это функциональность, ассоциированная с модулем, сообщающая как взаимодействовать с содержимым модуля. Модуль может иметь несколько Facets.
В IntelliJ IDEA Ultimate Edition имеется настройка в параметрах проекта, позволяющая назначать Facets, в отличие от Community Edition, где назначение Facet доступно лишь из API.
Строение проекта
С точки зрения разработчика плагина, структура проекта выглядит так, как показано на рисунке ниже.
Проект содержит один или несколько модулей. Каждый модуль включает исходный код плагина и вызывает упорядоченный набор сущностей, связанных с SDK и библиотеками. Модуль может иметь набор Facets.
Работа с файлами проектов, модулями, библиотеками
IntelliJ IDEA сохраняет конфигурационные данные в XML-файлы. Список этих файлов зависит от формата проекта.
Для формата проектов, основанного на файле, информация сохраняется в сам файл проекта «имя-плагина.ipr». Информация о модулях сохраняется в файлы «имя-модуля.iml», которые создаются для каждого модуля.
Для формата проектов, основанного на директории, настройки проекта сохраняются в несколько XML-файлов в поддериктории «.idea». Каждый файл ответственен за свой набор настроек и имеет соответствующее название: projectCodeStyle.xml, encodings.xml, vcs.xml и так далее. Данные модулей сохраняются в *.iml-файлах.
Для того чтобы работать с проектами и файлами проектов существуют несколько интерфейсов и классов:
- интерфейс Project;
- абстрактный класс ProjectRootManager;
- абстрактный класс ProjectManager;
- интерфейс ProjectFileIndex.
IntelliJ IDEA предоставляет следующие классы для работы с модулями:
- абстрактный класс ModuleManager;
- интерфейс Module;
- абстрактный класс ModuleRootManager;
- интерфейс ModuleRootModel;
- класс ModuleUtil;
- интерфейс ModifiableModuleModel;
- интерфейс ModifiableRootModel.
Для получения списка библиотек можно перечислить все сущности модуля и выбрать экземпляры интерфейса LibraryOrderEntry. Для получения классов, содержащихся в библиотеке можно использовать метод Library.ModifiableModel.getUrls.
Для работы с facet существуют классы DefaultFacetsProvider и Facet.
Виртуальная файловая система IntelliJ IDEA
Виртуальная файловая система (VFS) – это компонент IntelliJ IDEA, инкапсулирующий большинство функций для работы с файлами. Служит для следующих целей:
- предоставление универсального API для работы с файлами независимо от их физического местоположения (на диске, в архиве, на FTP-сервере и т.д.);
- отслеживание изменений в файлах и предоставление как старой, так и новой версии их содержимого;
- предоставление возможности указать дополнительную информацию для файла внутри VFS.
Для того чтобы предоставить две последние функции, VFS создает снапшоты (слепки) содержимого на жестком диске. В снапшот попадают только те файлы, которые были запрошены хотя бы один раз через программный интерфейс VFS и асинхронно обновляет их в соответствии с изменениями, происходящими на диске.
Снапшоты работают на уровне приложения, поэтому даже при множественных ссылках из различных проектов, данные сохраняются в единственном экземпляре.
Все операции по доступу проходят через снапшот, если запрошенная информация недоступна, то она подгружается с диска. Содержимое файлов и список файлов в директории сохраняются, только если запрошена специфическая информация, в остальных случаях сохраняется только метаинформация (имя, размер и т.д.).
Все операции по записи – синхронны, т.е. данные записываются на диск немедленно.
IntelliJ IDEA выполняет асинхронную операцию полного обновления содержимого при запуске. Также, по-умолчанию, обновление происходит при переключении из другого приложения, но это поведение можно настроить на вкладке «Settings | Synchronize files».
Операция синхронизации основана на временных метках, если дата модификации не изменилась, то IDEA не обновляет содержимое файла. По возможности IntelliJ IDEA использует встроенные в операционную систему наблюдатели за файлами (inotify, epoll и т.д.).
События виртуальной файловой системы
Все изменения, происходящие с виртуальной файловой системой, как результат выполнения операции обновления или из-за действий пользователя называются событиями виртуальной файловой системы.
Наиболее эффективный путь слежения за событиями VFS – это реализация интерфейса BulkFileListener и подписка на VirtualFileManager.VFS_CHANGES. Этот API предоставляет список всех изменений, произошедших во время операции обновления, что позволяет производить пакетную обработку. Альтернативный путь – реализация интерфейса VirtualFileListener и регистрация его посредством VirtualFileManager.addFileListener(). Этот вариант позволяет обрабатывать изменения поодиночке.
Не стоит забывать, что обработчики работают на уровне приложения, следовательно, получают события ото всех открытых пользователем проектов. Поэтому в первую очередь стоит отфильтровать только релевантные активному проекту события.
При обновлении создаются события только для файлов, загруженных в снапшот. Поэтому если одиночный файл был загружен через VirtualFile.findChild(), то изменения, происходящие с ним будут отслеживаться, а с соседними по директории – нет.
Продолжение следует.
Автор: Lucyfer