Статьи

Интервью: Уилфред Спрингер о битовом синтаксисе для Java

Главный научный сотрудник Xebia в Нидерландах Уилфред Спрингер создает основу для работы с двоично-закодированными данными. Этот фреймворк называется Preon, и ниже Уилфред объясняет его назначение, его архитектуру и как начать использовать его самостоятельно.

Можете ли вы рассказать нам немного о себе, своем прошлом и своих интересах в программировании?


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


Я был в мире Java целую вечность.
Более 10 лет назад я присоединился к практике Java-центра Sun, главным образом потому, что мой работодатель в то время не мог привлечь меня к проекту Java. После шести лет работы в Sun я присоединился к
TomTom , где мы с нуля создали замечательную команду Java. В TomTom основная часть нашей работы заключалась в создании служб, облегчающих навигационное устройство, и услуг, связанных с потреблением огромных объемов данных с устройства. Это в основном то, где Преон родился.


Больше всего в мире Java мне нравится его сообщество.
Это огромный! И так много всего происходит, что вы не можете видеть прямо. Мне это нравится, и я также пытаюсь внести свой собственный справедливый вклад. Я отвечаю за пару проектов с открытым исходным кодом и довольно часто выступаю на нескольких конференциях по Java, в основном о проектах с открытым исходным кодом, в которых я участвую.

Что такое Преон, в одном предложении?


Preon — это
декларативная структура привязки данных для двоичных данных . Preon предназначен для двоичного кодирования, что JAXB для XML, а Hibernate — для реляционных баз данных.

Какую проблему пытается решить Преон? Кому это должно помочь?


Вопреки распространенному распространенному мнению, не все данные на вашем диске и проходящие через сеть кодируются в XML или другой текстовый тип кодирования. На самом деле я провел быстрый опрос и обнаружил, что большинство файлов на моем жестком диске,
которые закодированы в недвоичном формате, — это файлы, которые у меня есть на диске, потому что я разрабатываю на Java. Вспомните исходные файлы Java, Javadoc на основе HTML, конфигурацию промежуточного программного обеспечения на основе Java и т. Д. Я провел такой же опрос на жестком диске моей жены и обнаружил, что почти все ее файлы являются двоичными файлами. Тем не менее, почему-то у нас есть сильное предпочтение форматированию текстового кодирования в мире Java. Вы удивляетесь, почему.


Я могу вспомнить хотя бы одну причину: Java, как известно, плохо работает с двоично-закодированными данными. Вы не согласны? Я ссылаюсь на
ошибку 4504839 и отдыхаю в моем случае. Этот отчет об ошибке о Java не поддерживает unsigned int. Работа с неподписанными int-данными в Java просто довольно болезненна. Вы должны сделать много маскировок и сдвигов, чтобы иметь возможность разобраться с этим разумным способом. И это отстой, поскольку почти все известные мне двоичные форматы данных постоянно читают неподписанные данные повсюду. Просто выкопайте описание произвольного формата файла в Википедии, и вы сможете это подтвердить.


Однако поддержка unsigned int не единственная вещь, отсутствующая в Java. Другая особенность, которой очень не хватает, — это поддержка закодированных битовых данных. Существует множество форматов файлов, в которых используются потоки битов, а не байты. Фактически, в этих случаях поток битов часто не выровнен с потоком байтов. Таким образом, последовательность битов, представляющих определенный атрибут, может очень хорошо пересекать границы одного байта. И у Java нет ничего, чтобы помочь вам в этом. Следовательно, решение этой проблемы возлагает на разработчика огромное бремя.


Сказав все это, сложность работы с двоично-закодированными данными — не просто проблема Java. Это общая проблема. В TomTom у нас было две отдельные базы кода для работы с форматом файла двоичной карты: одна база кода для декодирования данных и одна для кодирования данных. Синхронизация этих двух баз кода
и документации требовала огромных усилий. Нетрудно понять, как это нежелательно.


Все это решает Преон.
Preon позволяет вам захватить структуру закодированного двоичного формата
один раз , и сопоставление со структурой данных в памяти один раз, и получить декодер, кодер (скоро) и описание формата файла бесплатно .

Как это по сравнению с конкурентами?


Там действительно не так много конкуренции в этом пространстве, если вы не говорите о других языках.
Прежде всего, есть несколько академических инициатив по захвату битового формата в DSL. Это включает в себя
Flavor семейство языков (Flavor, BFlavor, gFlavor) и BSDL (Bitstream Синтаксис Описание Language). Большая часть этой работы происходит из мира медиаформатов, в частности MPEG.


Аромат, наверное, лучший пример такого подхода.
Он определяет текстовую (не XML) грамматику для захвата структуры битового потока и имеет несколько инструментов для превращения этого в Java и C API. В принципе, мало чем отличается от Lex и YACC или ANTLR.


Хотя Preon разделяет ту же цель, что и Flavor, подход радикально отличается. Аромат начинается с описания синтаксиса. Preon начинается со структуры данных в памяти. Flavor сгенерирует код, и вам просто нужно с этим справиться. Preon начинается с исходного кода и создает декодер во время выполнения. Аромат закрыт. Вы не можете расширить Flavor, не касаясь его исходного кода. Преон расширяемый. Он имеет ряд точек подключения, чтобы добавить поддержку ваших собственных методов сжатия.


Preon также имеет некоторые общие черты с синтаксисом битов Эрланга.
(На
OOPSLA 2009 он будет представлен как битовый синтаксис для Java.) Разница в том, что поддержка битового синтаксиса встроена в язык в Erlang; Preon предлагает его как библиотеку, построенную на языке. Поддержка битового синтаксиса Эрланга не расширяема. Поддержка Преона расширяема.

Можете ли вы описать архитектуру Preon?


Внутри Преона есть несколько слоев.
На нижнем уровне он предоставляет тип абстракции ByteBuffer для доступа к данным битового потока, называемый BitBuffer. Это абстракция, которая позволяет вам быстро получать доступ к данным в виде потока битов, полагаясь на структуру, чтобы поддерживать указатель на текущее местоположение и иметь дело с параллельным доступом.

Рисунок 1. Архитектура Preon


Декларативный фреймворк для привязки данных находится на верхнем уровне.
Вы объявляете отображение из структуры данных в памяти в ее представление потока битов, используя аннотации. Во время выполнения вы передаете ссылку на корневой класс этой структуры данных в Preon, и он вернет вам кодек для всей структуры данных. Если у вас есть экземпляр Codec, использовать его просто: вы просто используете один из вспомогательных методов класса Codecs, и он вернет вам экземпляр структуры данных на основе переданного входного источника.

Пример 1. Преон декодирования цвета

class Color {
@Bound byte red;
@Bound byte green;
@Bound byte blue;
}

Codec<Color> codec = Codecs.create(Color.class);
Color color = Codecs.decode(codec, new byte[] { 0x12, 0xff, 0x34 });


Есть несколько важных вещей, которые нужно знать о Преоне. Прежде всего, когда вы спрашиваете Preon о кодеке, он на самом деле возвращает цепочку кодеков. Кодек, который вы получите, передаст другим кодекам более точные обязанности. (См.
Рисунок 2, «Передача кодеков кодекам» .) Итак, если у вас есть цветной кодек, а цветовая модель основана на модели RGB, то этот кодек цвета, скорее всего, будет внутренне делегировать три кодека для байты: один для значения красного компонента, один для зеленого компонента и один для синего компонента.


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

Рисунок 2. Делегирование кодеков кодекам


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


В-третьих, Preon создаст кодек, который будет загружать данные максимально лениво. Если формат позволяет пропустить список элементов, и вы еще не читаете элементы из этого списка, то Preon вернет список, но затем пропустит данные в этом списке. Только если вам нужен элемент из этого списка, он вернется и извлечет его из основного потока битов. Теперь файл карты TomTom служит отличным примером того, почему это необходимо: на диске он уже использует 1,5 ГБ пространства. Представьте себе распаковку этого сжатого файла в память за один проход. Это наверняка взорвало бы вершину кучи Java на 32-битной виртуальной машине.


Итак, это лишь некоторые из возможностей, которые предлагает Preon.
Здесь я хочу упомянуть еще одну вещь: Preon также генерирует гиперссылочную документацию из вашего «описания синтаксиса». Цель состоит в том, чтобы создать описание, сравнимое с написанными человеком описаниями, которые вы найдете в Википедии, и Преон уже довольно близко подходит к этому.

Рисунок 3. Документация, сгенерированная Preon

Как я могу сделать плагин для Preon? Какие плагины было бы полезно сделать?


У Preon есть пара точек подключения.
Как я уже говорил ранее, довольно легко создать поддержку для вашего собственного конкретного типа сжатия. Скажем, вам нужна поддержка
закодированных данных Хаффмана . В этом случае вы бы:


  1. Прежде всего, определите аннотации, которые инициировали бы создание кодека Хаффмана, когда он встречает закодированный атрибут Хаффмана. Это довольно просто. Вам просто нужно определить атрибуты, необходимые для настройки кодека Хаффмана, например, ссылку на двоичное дерево, определяющее способ кодирования данных. Давайте назовем эту аннотацию @HuffmanCoded.


  2. Далее вам необходимо реализовать
    CodecFactory . Помните, мы хотим убедиться, что всякий раз, когда Preon встречает атрибут @HuffmanCoded в классе, он будет создавать экземпляр кодека Хаффмана. Реализуя CodecFactory, вы в основном создаете компонент, который получит возможность распознавать атрибуты этого типа, и создаете экземпляр этого кодека.


  3. В-третьих, вам нужно создать настоящий кодек Хаффмана.
    Интерфейс
    кодека
    не очень сложен, поэтому большая часть работы будет заключаться в реализации операции decode (), но все зависит от сложности техники кодирования, которую вы реализуете.


  4. В рамках реализации

    Кодека
    вам также необходимо реализовать
    CodecDescriptor . То есть, если вы хотите, чтобы Preon выплевывал полезную документацию. Если вас это не волнует, вы можете просто вернуть CodecDescriptor по умолчанию.


  5. И последнее, но не менее важное: вам нужно передать ссылку на CodecFactory, если вы создаете экземпляр своего кодека для определенной структуры данных.
    Preon возьмет этот CodecFactory и добавит его в список CodecFactories, который он уже поддерживает из коробки. Теперь он распознает необходимость создания экземпляра вашего кодека Хаффмана, как только встретит аннотацию @HuffmanCoded.


Вот и все.
Это много работы? Я так не думаю, но что более важно, вы добавили не только поддержку кодирования Хаффмана для определенного формата файла, но и для
всех форматов файлов, которые полагаются на строки, закодированные Хаффманом. Как это круто?

Как / когда вы решили сделать Преон?


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


Теперь этот проект был в итоге заброшен.
Однако я почувствовал, что в способе работы есть что-то невероятно привлекательное, и начал работать над этим в свободное время. Это означает, что я в основном перестроил фреймворк с нуля, пытаясь использовать его в паре разных форматов кодирования.


Удостовериться, что Preon поддерживает файлы классов Java (то есть использование Preon для создания файлов классов Codec for Java), оказалось особенно сложной задачей.
Способ поиска данных в пуле констант, по меньшей мере, неудобен. Однако, в качестве основы для поддержки двоичного кодирования в целом, вы не можете сделать исключение для неуклюжих конструкций.

Вы представляли Preon на нескольких конференциях. Какая была обратная связь?


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


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


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

вместо этого
полагаться на кодирование BER
ASN.1 . Теперь я думаю, что это будет ошибкой. Кодировка BER или двоичные стандарты XML-кодирования хороши, если ваша модель Infoset, но во многих случаях это не так, и есть гораздо более быстрые способы доступа к данным, если вы признаете это.


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


То же самое относится ко всем другим известным (основанным на энтропии) методам сжатия.
Вы можете получить много пробега от этих методов, и было бы напрасно игнорировать это. Фактически, именно поэтому большая часть данных на вашем диске все еще имеет двоичное кодирование.

Пожалуйста, скажи несколько слов о начале работы с Preon. Что мне нужно скачать и какую первую документацию мне следует прочитать?


Если вы хотите узнать больше о Preon, есть несколько документов, доступных на
веб-сайте и на Scribd. Я предлагаю вам сначала прочитать введение , а затем проверить примеры.


Вы можете проверить примеры, проверив источники, но вы также можете проверить их
онлайн в Fisheye . Проверьте модуль preon-samples. Я бы посоветовал вам начать с примера Bitmap в preon-sample-bmp. Затем вы можете изучить пример preon-sample-bytecode, который в основном содержит источники декодера байт-кода Java без единой строки императивного кода.


Я полагаю, что вы готовы пойти после этого
Библиотеки Preon можно скачать из репозитория Maven, найденного
здесь , но вам также нужно будет добавить ссылки на репозитории Limbo и Pecia, поскольку Preon зависит от этих библиотек.

Пример 2. Конфигурация Maven POM

<dependencies>
<dependency>
<groupId>nl.flotsam.preon</groupId>
<artifactId>preon-binding</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
...
<repositories>
<repository>
<id>limbo-repository</id>
<url>http://limbo.sourceforge.net/repository</url>
</repository>
<repository>
<id>pecia-repository</id>
<url>http://pecia.sourceforge.net/repository</url>
</repository>
<repository>
<id>preon-repository</id>
<url>http://preon.flotsam.nl/repository</url>
</repository>
</repositories>


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

Какое будущее у Преона? График? Особенности, которые вы хотели бы иметь? Взносы, полученные от других?


Поддержка кодирования — это первая вещь в моем списке пожеланий для следующего выпуска.
Затем появляется возможность комментировать hexdumps, чтобы объяснить, что внутри, на основе метаданных, собранных Preon. Это будет просто потрясающе. Больше не нужно проверять hexdump вручную, вместо этого нажмите на кусок hexdump и попросите Preon объяснить, что это значит.


Кроме этого, я хотел бы иметь больше примеров использования Preon.
Я начал изучать файлы Flash на днях, и я думаю, что это интересный случай для Preon.


Я еще не получил никаких взносов от других людей, за исключением некоторых из моих бывших коллег.
Тем не менее, я хотел бы пригласить кого-нибудь, чтобы попробовать его конкретную проблему. Я был бы рад помочь вам и объяснить Преону, если документация не дотягивает. Пришло время признать, что мы пишем программы, которые будут выполняться компьютерами, а не людьми. Компьютеры гораздо лучше справляются с двоичными данными, чем с данными, читаемыми человеком. И я думаю, что Preon — отличный инструмент, помогающий заставить компьютер делать то, что у него лучше всего.