Четырехпроводный аналоговый транк на Cisco

Каналы ведомственных и отраслевых систем селекторных совещаний имеют общую особенность — работа с четырехпроводными окончаниями тональной частоты.

В частности в энергетической отрасли это наследие АДАСЭ (Аппаратура Дальней Автоматической Связи Энергосистем), использовавшейся и продолжающей использоваться в системах диспетчерской и технологической связи предприятий энергетики.

Каналы дальней связи используются в качестве транков между площадками, участвующими в селекторном совещании, а непосредственно на площадках устанавливается оборудование АСС БР (Аппаратура Селекторной Связи Блок Распределительный), работающее с четырехпроводными окончаниями и обеспечивающее подключение абонентских комплектов, согласование уровней приема-передачи и организацию системы «перебоя».

Ввиду того что данные системы связи давно не получают развития и морально устарели, при расширении числа площадок участников совещания возникают сложности с организацией четырехпроводных транзитов — каналообразующее оборудование АДАСЭ на площадке отсутствует, а его монтаж нецелесообразен.

Но правила устанавливаем не мы, а данная система существует и продолжает эксплуатироваться. Кроме того возникают ситуации, когда оборудование на площадке уже имеется и работает со 100% использованием возможного ресурса, а задача стоит в организации резервного канала связи, либо включения в существующую систему удаленного регионального ведомства, что еще более усложняет реализацию, так как точка включения в данном случае может находиться в десятках, а то и сотнях километров от площадки.

На данный момент можно найти оборудование первичных мультиплексоров, обеспечивающих работу с четырехпроводными каналами ТЧ (оборудование типа ОПМ-30, МП-30, НТС-1100 и т.п.). Данный вариант предполагает установку двух полукомплектов оборудования (стативы, процессорные платы, платы ТЧ, блоки питания и т.д.) и организацию между ними канала Е1 либо Т1, что потребует еще и наличия каналообразующего оборудования.

А если ничего этого нет, либо развертывание нецелесообразно, но есть оборудование Cisco и в точке присутствия канальных окончаний АДАСЭ и на площадке участника с организованной передачей данных по протоколу Ethernet? Более того, маршрутизаторы Cisco «голосовые» VK9 и уже используются для служебных каналов телефонной связи. Рассматриваемая ситуация приведена схематически на Рис.1.

Возможны два варианта. Первый вариант предполагает преобразование четырехпроводной схемы в двухпроводную схему ТфОП и использование голосовых модулей Cisco типа VIC FXO/FXS с дальнейшей передачей голоса по протоколам VoIP. При этом применяемые преобразователи помимо реализации дифференциальной схемы должны понимать сигнализацию ТфОП, но в четырехпроводную схему сигнализацию уже не передавать (сигнализация в четырех проводных окончаниях каналов селекторной связи не передается, соединения устанавливаются операторами на узлах связи). То есть устройство должно принять сигнал вызова из 2-х проводной схемы ТфОП и просто установить соединение по 4-х проводной схеме с разделением речевых каналов TX — RX и возможностью настройки требуемых уровней сигнала (-13 и +4дБ). Такой вариант сложен в реализации ввиду отсутствия устройств подобного типа, а имеющиеся предложения несут суровый отпечаток «наколенной» сборки и добиться стабильной работы от них не удалось. Невозможно использовать и штатные СУВ, КТН и прочие модули сопряжения каналов, использующие одночастотный код сигналов взаимодействия и управления без выделения сигнального канала, т.к. данную сигнализацию просто нечем принять, обработать и установить соединение. В случае обрыва соединения система должна будет автоматически восстановить канал (по сути, автонабор номера), что потребует еще организации программных «костылей» и дополнительно снизит надежность схемы. Есть еще целый спектр вопросов требующих решения в данной реализации, но и озвученных более чем достаточно для того чтобы признать данное решение неприемлемым.

Второй вариант более стандартный, но, как и вся поднятая тема, отдает некоторой «экзотикой». Это использование голосовых модулей Cisco VIC E&M. Аналоговые линии с сигнализацией E&M используют шести или восьми проводную схему. Возможна реализация как двух проводной, так и четырех проводной схемы передачи речевых сигналов, а для сигнализации используются выделенные линии из двух или четырех проводников в зависимости от используемого типа сигнализации E&M. Сам стандарт считается устаревшим, но производителями пока поддерживается. У компании Cisco есть два поколения двух портовых голосовых модулей VIC-2E/M и VIC2-2E/M. При выборе модулей нужно убедиться, что роутер и версия IOS поддерживают данный тип VIC (например серия 2800 не работает с VIC-2E/M, в то время как на Cisco 1760 проблем с ними не будет). Вариант с четырехпроводной передачей голоса нам подходит, но как быть с сигнализацией, которая использует отдельные провода и реализуется путем замыкания их либо на землю, либо на станционную батарею для индикации состояния интерфейса, ведь данную сигнализацию конечное оборудование не поддерживает.

Сигнализация E&M имеет пять типов. Подробно на каждом типе останавливаться не будем, отметим только, что в нашем решении будем использовать сигнализацию E&M Type V с немедленной передачей сигналов. При такой сигнализации коммутация аналоговых каналов происходит без подтверждения готовности или проверки занятости голосовых портов. Но это и нужно, так как цепи сигнализации вообще не используются (нам их просто нечем принять), а сам канал предполагается использовать в режиме «всегда включен». При необходимости, освобождение полосы пропускания от голосового трафика по окончании селекторного совещания производится оператором, сопровождающим совещание, путем программного отключения одного из голосовых интерфейсов.

Пример конфигурирования голосовых портов (модули VIC2-2E/M установлены в слотах 0/2/0 маршрутизаторов Cisco 2801):

< — Площадка участника —>

interface FastEthernet0/0
ip address X.X.X.X 255.255.255.252
h323-gateway voip bind srcaddr X.X.X.X

dial-peer voice 101 pots
destination-pattern 101
port 0/2/0

dial-peer voice 102 voip
destination-pattern 102
session target ipv4:Y.Y.Y.Y
codec g728
no vad

voice-port 3/0
operation 4-wire
type 5
signal immediate
input gain 14
output attenuation -6
no echo-cancel enable
timeouts call-disconnect 3
connection trunk 102

< — Площадка канальных окончаний АДАСЭ —>

interface Loopback0
ip address Y.Y.Y.Y 255.255.255.255
h323-gateway voip bind srcaddr Y.Y.Y.Y

dial-peer voice 102 pots
destination-pattern 102
port 0/2/0

dial-peer voice 101 voip
destination-pattern 101
session target ipv4:X.X.X.X
codec g728
no vad

voice-port 0/2/0
operation 4-wire
type 5
signal immediate
input gain 14
output attenuation -6
no echo-cancel enable
timeouts call-disconnect 3
connection trunk 101 answer-mode

Answer-mode устанавливается только с одной стороны, т.е. одна сторона выступает инициатором транка, а вторая отвечает. Параметры input gain и output attenuation выставляются путем подачи тестового сигнала 800Гц и настройки голосового тракта под стандартные уровни +4дБ прием и -13дБ передача с последующей проверкой голосом.

Системы АДАСЭ используют четырехпроводные аналоговые линии ТЧ, не имеющие отдельных цепей сигнализации. Сигнализация взаимодействия передается в речевом канале на частотах 1200 Гц и 1600 Гц ± 5 Гц. Теоретически такой транк можно использовать и для включения каналов АДАСЭ, но такой режим работы не проверялся.

Рассматриваемое решение реализовано и используется в действующих сетях. http://habrahabr.ru/post/251605/

Химия геймдева или как манипулировать игроками

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

1. За пределами алхимии
Недавно мне попалось на глаза описание алхимии, той волшебной псевдонауки прошлого тысячелетия, которая эволюционировала в современную химию. На мгновение я подумал, что авторы как будто описывали сегодняшнюю ситуацию в области гейм дизайна.

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

А что если бы мы декодировали эти системы и превратили бы их в практическую методику создания игр?

2. Основы модели гейм дизайна
В попытке дать определение играм внимание фокусировали на механических элементах игры — примитивных действиях, которые система позволяет выполнять игроку. Такой подход вынуждает относиться к играм, как к автономным логическим системам.

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

Игры — не математические системы. Это системы, которые всегда включают энергичного человека, полного желаний и эмоций, являющегося ядром системы. Чтобы точно описать игру, нужна работающая психологическая модель игрока.

Модель игрока
Наша модель игрока предельно проста – это субъект, который начинает действовать, сознательно или подсознательно, чтобы максимально изучить новые умения с выгодой для себя. Он получает удовольствие от успешно приобретенных навыков.

Три ключевых понятия модели игрока:

Умение Побуждение к обучению Восприятие выгоды

Умение

Умение – это знание, которое игрок использует, чтобы управлять игровым миром. Некоторые навыки основаны на понятиях — умение управлять картой, в то время как другие весьма физические — стучать по гвоздю молотком.

Побуждение к обучению

Игра — инстинктивна. В современных условиях, когда мы не активно выполняем действия, связанные с пропитанием и жильем, люди начинают играть по умолчанию. Более сильные механизмы в виде скуки или разочарования подталкивают к действию. При наличии свободной минуты, дети бросаются в игру с кубиками или куклами, а взрослые имеют более сложные хобби. Это говорит о необходимости стимулирования людей, ведь одиночное заключение до сих пор остается одним из самых жестких наказаний для закоренелых преступников.

Обратная сторона медали – мы хотим вознаграждения за обучение. Удивительно, но игровой термин “веселье” возникает в процессе усвоения знаний, навыков и инструментов. Когда вы узнаёте что-то новое или что-то понимаете так хорошо, что можете использовать эти знания в своих целях, вы испытываете радость.

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

Восприятие выгоды

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

Осознание выгоды важнее, чем объективное измерение ценности. Люди не логичные существа. Мы знаем, что люди имеют твердые убеждения по тому, как они взвешивают свои действия. Например, они часто необоснованно рискуют, потому что не в состоянии правильно оценить реальные шансы. Люди имеют субстанциональные ограничения, в зависимости от того, сколько информации они могут принять во внимание при вынесении каких-либо решений. Многие решения принимаются на основе весьма предсказуемых реакций шестого чувства, которые имеют свои собственные подсознательные правила.

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

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

Как модель работает в Марио:

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

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

То, что мы называем игрой

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

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

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

Связи игровых механик

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

Схема связей игровых механик тетриса в полный рост

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

Процесс взаимодействия игроков с цепью умений

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

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

4. Положение элементов в цепи
Цепь умений обеспечивает достаточно полезной информацией о состоянии игрока, в то время, как он занят игрой. Представьте, что цепь умений — это панель приборов, которая загорается, как только игрок преуспел. В любой момент времени вы можете увидеть следующую информацию:

Освоенные умения: навыки, которые недавно были освоены. Частично освоенные умения: навыки, которыми игрок еще не овладел в совершенстве. Новые умения: навыки, которые игрок только открыл для себя. Активные умения: навыки, которые игрок активно использует. Сгоревшие умения: умения, к тренировке которых игрок потерял интерес.

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

Активные умения

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

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

Сгорание

Игроки не всегда строят связи между навыками. Они осваивают новое умение, они играются с ним, но не могут найти ему интересного применения. Это называется сгоранием.

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

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

Ранняя стадия сгорания

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

Поздняя стадия сгорания

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

К примеру, у нас есть платформа, на которую нужно запрыгнуть, но на ней нет ничего полезного для игрока. Игрок прыгает на платформу, не обнаруживает ничего интересного и вскоре прекращает прыгать по платформам вовсе. В результате у него атрофируется умение прыжка. Если игроку не нужно прыгать на платформы, тогда зачем ему вообще прыгать?

Сгорание – лучший помощник в тестировании!

Сгорание — очень мощный сигнал, что наша игра не в состоянии удерживать внимание игроков. Мы можем понять в какой момент на каком навыке происходит сгорание. Если отслеживать сгорания наряду с другими состояниями умений, можно точно определить проблемные участки игры.

5. Продвинутые элементы цепи умений
Мы рассмотрели основные элементы цепи умений и теперь можем применить это на практике. Но есть еще кое-что, что неплохо бы усвоить.

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

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

Недостаток нужных навыков

Если игроку не хватает ожидаемых от него навыков, он не сможет воспользоваться базовыми навыками в нашей игре. В нашем примере с прыжками представьте себе игрока, который не понимал, что нужно нажать кнопку на джойстике для того, чтобы что-то сделать. Такой пример может показаться нелепым, но с этим сталкиваются многие не-геймеры, когда они встречаются с чудовищно сложным современным контроллером. Многие дизайны игр автоматически предполагают способность ориентироваться в 3D пространстве с помощью двух неудобных маленьких аналогичных друг другу кругляшей и множеством непонятных кнопок. Пользователи, у которых нет этого умения, поддаются отчаянию, не видя подавляющее количество контента.

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

Опасности базовых навыков

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

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

Отвлекающий маневр

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

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

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

6. Заключение
Использование цепи умения

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

Создание цепи умений дает вам следующую информацию:

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

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

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

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

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

P.S. Спасибо за гигантскую помощь в переводе Наталье Андреевой ну и ссылка на оригинал http://habrahabr.ru/post/251623/

Программа вывода лабиринта в 13… нет. 10 байт!

В прошлом, найдя интересное решение при написании демки, я тихо его использовал или же хвастался узкому кругу друзей на демосцене. Но теперь мои возможности достигнуть чего-либо на демосцене подошли к концу, а турниры по минималистскому программированию не проводятся, поэтому я решил написать в блог о своём достижении: генераторе лабиринтов объёмом всего в 13 байт машинного кода x86.

Чтобы понять суть достижения, вам надо знать о команде 10 PRINT. Это строчка кода Commodore 64 BASIC, которая при запуске создаёт бесконечный лабиринт. Конечно, её вывод – это не настоящий лабиринт, входа и выхода там нет, и полно закрытых помещений и тупиков. Но выглядит он как лабиринт. Поражает то, как простая команда выдаёт бесконечно сложный шаблон.

Также под названием «10 PRINT» издана книга на 324 страницы. Она рассказывает про код, искусство, восприятие, культуру, случайности, лабиринты и всё остальное. Рекомендуется к прочтению всем, кто интересуется программированием – там для каждого найдутся интересные темы, которые к тому же очень хорошо освещены и оформлены.

42 bytes
Вернёмся к коду. В книжке «10 PRINT» я прочёл, что код из BASIC можно представить в более компактном виде в машинном коде C64. Там же была задачка для читателей. Рекорд был поставлен товарищами 4-Mat и Wisdom, которые впихнули решение в 15 байт. Мне стало интересно, а как это можно сделать на x86. Вот я и написал первую версию этой программы:

; Простая программа, имитирующая вывод команды "10 PRINT" ; В этой версии используется "настоящий" рандом и не делается ; никаких предположений о содержимом регистров. ; Также мы переходим в режим низкого разрешения ; чтобы добиться более приемлемого соотношения сторон ; и выходим из программы по окончанию вывода лабиринта. init: mov ax,0001h int 10h ;выставляем цветной режим 40×25 xor bh,bh ;видео задали, поэтому vidpage=0 mov cx,(40*23) ;количество символов для вывода getrnd: xor ax,ax ;чтобы получить al=0 pushf cli ;запрещаем прерывания, чтение таймера должно быть атомарным out 43h,al ;запираем регистр счётчика in al,40h ;читаем lobyte счётчика mov ah,al in al,40h ;читаем hibyte счётчика popf ;включаем прерывания xchg ah,al ;теперь содержит 8253 raw 16-bit word pickch: shr ax,1 ;BIOS инициализируется в count-by-2, первый бит всегда lo shr ax,1 ; carry = "случайный" бит mov al,’\’ jc writec ;если бит взведён, сразу пишем mov al,’/’ ;иначе выбираем другой символ writec: mov ah,0eh ;выводим символ в режиме телетайпа int 10h loop getrnd int 20h ;выходим в DOS

Этот код ведёт себя «прилично», не делает предположений о состоянии процессора и завершает работу (оригинальная версия 10 PRINT работала бесконечно). Случайное число более-менее неплохо генерится из железячного таймера, который каждую секунду отсчитывает от 65535 до 0. При компиляции a86 выходит 42-байтовый файл .COM

Размер сильно отличается от C64 в двух местах: генератор случайных чисел и выбор символа. У C64 преимущество в символах, т.к. оба слеша находятся рядом в PETSCII. Если у вас есть рандомный бит, его можно просто добавить к первому слэшу, и получить либо его, либо второй слэш. При использовании ASCII это не прокатит, приходится использовать условие.

Затем для оптимизации я решил убрать условие выбора. При сдвиге кода одного из слэшей оба слэша начинают отличаться всего одним битом.

"/"=2f и "\"=5c 2f=00101111 5c=01011100

Поэтому можно заменить кусок «pickch»:

pickch: shr ax,1 ;BIOS инициализируется в count-by-2, первый бит всегда lo push cx ;Сохраняем счётчик цикла mov cl,al ;копируем случайное число в cl and cl,1 ;cl теперь 0 или 1 mov al,’\’ ;задаём символ ‘\’ shr al,cl or al,cl ;если cl=1, то ‘\’ превращается в ‘/’, иначе – без изменений

Это было круто, но размер в результате увеличился до 48 байт. Пришлось отбросить идею.

Ещё одна оптимизация – убрать процедуру вывода writec, и просто пихать байты в видеопамять. Это убирало два байта с процедуры вывода, но добавляло 4 байта на настройку (и 5, если оставаться в пределах стандарта 8086), поэтому это тоже пришлось отбросить.

25 байт
Я внимательнее посмотрел на самый большой отрезок программы – генератор случайных чисел. Очевидно, что качество генератора нас не особо заботит – главное, чтобы не было очевидных повторений. Поэтому я заменил блок «getrnd» одной инструкцией LODSB. Она вынимает байт из памяти и переходит на следующий, поэтому можно читать последовательность из памяти. А место, с которого я начал читать – то, куда показывает DS:SI при старте программы. Для COM-файла в DOS он показывает на начало самой программы. Поэтому мой «случайный» поток определялся самим скомпилированным кодом, и всяким мусором от других программ. В результате код сильно уменьшился до 25 байт.

15 байт
Тут я уже раззадорился – появилась возможность приблизиться к размеру версии C64. Я избавился от всяких телодвижений типа смены видеорежима, чистого выхода (теперь программа работает вечно) и инициализации регистров. В конце это выглядело так:

init: mov ah,0eh ;10h для вывода символов в режиме телетайпа getrnd: lodsb ;прочтём байт с того места, куда указывает DS:SI pickch: shr al,1 ;carry = "случайный" бит mov al,’\’ jc writec ;если бит взведён, сразу пишем mov al,’/’ ;иначе выбираем другой символ writec: int 10h ;выводим символ jmp getrnd ;бесконечный цикл

15 байт – это успех!

13 байт
Мне всё казалось, что я могу улучшить блок «pickch». Блок начинается с присваивания случайной величины в флаг carry, но у 8086 есть флаг чётности, который взводится автоматически в некоторых случаях. К сожалению, LODSB флаги не взводил. Математическая операция взвела бы флаг чётности, но такая операция заняла бы больше места. Если бы найти однобайтовую инструкцию, которая делает то же, что LODSB, и взводит флаг чётности в зависимости от входных данных…

Есть такая инструкция! SCAS – загружает байт, сравнивает его с AL, и взводит флаг по результатам сравнения. Она предназначена для использования в цикле, но никто не мешает использовать её без цикла. И что в результате:

init: mov ah,0eh ;10h для вывода символов в режиме телетайпа getrnd: scasb ;прочесть с места ES:DI и сравнить с AL ;взводит флаг вместо вычитания pickch: mov al,’\’ ;выбрать символ jc writec ;если бит взведён, сразу пишем mov al,’/’ ;иначе выбираем другой символ writec: int 10h ;выводим символ jmp getrnd ;бесконечный цикл

И вот вам 13 байт. Работает даже на старых IBM PC, поскольку не использует инструкций от 80186+. Примерный вывод:

12 байт
Читатель Питер Ферье умудрился улучшить моё достижение на один байт

init: mov ax,0e5ch ;загрузим AH с cmd "запись символа" и AL с ‘\’ scasb ;прочесть с места ES:DI и сравнить с AL ;this sets flags similar to a subtraction pickch: jp writec ;Если флаг чётности взведён, переходим к выводу символа из AL mov al,’/’ ;иначе выбираем другой символ writec: int 10h ;вывести символ из AL jmp init ;бесконечный цикл

Брависсимо. Однако ж, читатель herm1t отметил, что если мы используем int 29h для вывода символа, то код сокращается до

11 байт
init: mov al, ‘\’ scasb jp writec mov al, ‘/’ writec: int 29h jmp init

Хитро. Но погодите-ка, это ещё не всё!

10 байт
init: scasb salc and al,’\’-‘/’ add al,’/’ int 29h jmp init

Питер нанёс ответный удар и стесал ещё один байт (этот код не будет работать на не-интеловских процессорах типа NEC V20 или V30). http://habrahabr.ru/post/251631/

Как сисадмину не остаться без работы

И при этом не попасться

Если ты админ, тебе нечем заняться, и твоя компания не нуждается в тебе ежедневно, то тебя, возможно, сократят в ближайшее время за ненадобностью. В данной статье я собрал лучшие практики от системных администраторов, которые умеют обеспечить себя работой настолько, что компания не может прожить без них и дня. Эти практики позволяют даже строить целые ИТ-отделы, там, где тебе было нечем заняться. Применять их или нет – остается на твое усмотрение:

1. Решай любые проблемы пользователей
Поставить любимую заставку на компьютер? Наклеить пленочку на мобильный телефон? Сверить два договора в ворде за юриста? Подрисовать бланк организации? «Посмотреть» домашний ноутбук? Делать работу за сотрудников компании и делать для них то, что не нужно компании – надежный способ заслужить любовь пользователей и получить больше работы. Можно даже дополнительных специалистов нанять в ИТ-отдел для этого – любая прихоть компании за ее деньги.

2. Ручная работа – всегда в цене

Если устанавливать операционную систему и приложения на рабочее место пользователя за одно нажатие клавиши и 15 минут, то у сотрудников компании может сложиться впечатление, что работенка у админа непыльная. По этой причине исключай автоматизацию в работе с пользователями: операционные системы ставь с диска вводом ключа лицензии вручную, байтик за байтиком ставь приложения, каждый раз ищи драйверы для принтеров в интернете и выполняй ювелирную настройку систем. Обновить платформу 1С на компьютерах – это вообще задача на неделю, а не на два клика мышью.

3. Не трать деньги компании на ненужные причиндалы
Дополнительный блок питания в сервер, диск горячей замены, стекируемый коммутатор, розетки и патч-панели для организации сети – именно на них ты можешь сэкономить денег компании, и именно благодаря их отсутствию руководство узнает, что сбои в ИТ не такая уж и редкость и системный администратор должен быть всегда рядом «на всякий случай».

4. Больше свободы для пользователей
Отсутствие ограничений на запуск неизвестных приложений, права локальных администраторов на компьютерах, антивирус, подконтрольный пользователю – это то, что позволяет чувствовать пользователям себя как дома и это то, что создает работу сисадмину. То пользователи вирус занесут на компьютер, то с корня диска C удалят «лишние» файлы, то компьютер тормозит из-за количества наставленных «ускорителей интернета». Ничего не поделаешь – за свободу можно и заплатить, наняв дополнительно парочку технических специалистов.

5. Приобретай только брендовые сервера

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

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

7. Делай работу быстро

Тратить рабочее время на планирование – это слишком затратно для компании и затягивает сроки проведения работ. Любую систему можно внедрить/модернизировать на раз-два, а все мелкие недочеты быстренько устранить за пару-тройку дней или даже еще быстрее, если будут помощники.

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

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

10. Создавай собственные разработки

Если компания не может позволить себе покупку какого-то решения, то для этого есть сисадмин, который может собрать почти такую же систему, но дешевле. Да, возможно у собранного админом решения будет парочка небольших недочетов, которые будут требовать регулярного обслуживания, но это же лучше, чем если бы компания потратила кучу денег на «то самое» решение. Конечно, никто кроме тебя в данной системе не разберётся, но это уже мелочи – ведь и без этого уволить тебя уже будет непросто.

P.S:

Если следовать перечисленным выше советам, то можно полностью занять одного ИТ-специалиста поддержкой 20-30 пользователей, а при размерах инфраструктуры в 100-150 пользователей уже создать свой ИТ-отдел на 5-6 человек. Если же вы в одиночку обслуживаете 50-60 пользователей и вас хотят сократить в связи с тем, что «в компании задач по обслуживанию на один день в неделю» – покажите эту статью руководству, и пусть они решат, хотят ли они, чтобы новый админ был всегда занят работой или нет. http://habrahabr.ru/post/251663/

Java EE, JCA и jNode 2.X announce

Доброго времени суток, %username%.
Скажу сразу, на 99% данный пост про Java EE Connector Architecture, с примерами кода. Откуда взялся 1% про Fidonet вы поймете в самом конце.

Резюме для ленивыхJMS и JCA — родственники, входящие принимает MessageDrivenBean, исходящие отправляются через ConnectionFactory.
Минимальный пакет для входящего соединения — 4 класса, для исходящего — 8 классов и настройка адаптера на стороне сервера приложений.
Дальше — только подробности и боль

Для начала — история вопроса и решение бизнес-задачи.

Постановка задачи
Мне поставили задачу об интеграции существующей бизнес-системы («система А» ) с другой системой, которая была разработана много лет назад и понимает только собственный протокол передачи данных («система B»). Модифицировать чужие системы нельзя, соответственно задача свелась к написанию некой шины/прокси. Интеграция состоит в передаче туда-сюда сообщений с конвертацией их в процессе из одного формата в другой.

Система «А» имела много современных механизмов интеграции, самым простым для использования были признаны веб-сервисы. Под это дело был оперативно запилен стандартный интеграционный скелет для JEE — JAX-WS+EJB+JMS для гарантированной доставки сообщения.
А вот для работы с системой «B» стандартных средств не было. Робкие попытки поработать с сетью из контекста EJB успехом не увенчались, гугл подсказал два варианта решения проблемы: костылить сервлеты для работы с non-http или написать JCA-адаптер. Понятно, что был выбран второй путь — с JCA я до этого не работал, а узнать что-то новое всегда интересно.

Исследование
Начав копать гугл, я достаточно сильно обломался. Везде писали, ЧТО именно нужно сделать ( коннектор, менеджер, адаптер итд ), но почти нигде не писали, КАК это сделать. Стандартный способ «посмотреть чужой код и понять процесс» дал сбой — чужого кода был такой мизер, что понять что-то мне не представлялось возможным.

Спасли меня две вещи: JSR 322 и единственный нагугленный адаптер на google code. Собственно, это и стало отправной точкой — задеплоив примеры из jca-sockets и открыв pdf, я начал разбираться и путем научного тыка понимать, как оно собственно работает.

Потратив около 16 часов на исследование и эксперименты, я выяснил следующее:

JCA-модуль имеет внутри себя две независимых части: «Входящие» и «Исходящие». Эти части могут быть как вместе, так и по-отдельности. Более того, их может быть несколько. Сам модуль регистритуется классом, реализующим javax.resource.spi.ResourceAdapter и указанным в META-INF/ra.xml, при этом ResourceAdapter нужен в первую очередь для работы с Входящими; Для Исходящих адаптер ничего не делает и его скелет можно даже не заполнять.

Входящие
Входящий канал биндится к MessageEndpoint’у ( обычно это @MessageDrivenBean; да-да, JCA это кишки JMS ) и активируется ActivationSpec’ом.
META-INF/ra.xml — описание ResourceAdapter’а и inbound потоков
ra.xml<connector xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/connector_1_7.xsd" version="1.7" metadata-complete="true"> <vendor-name>kreon-services</vendor-name> <eis-type>FidoNet</eis-type> <resourceadapter-version>2.5</resourceadapter-version> <resourceadapter> <!— Класс, который реализует javax.resource.spi.ResourceAdapter; config-property — поля, должны быть доступны через геттеры/сеттеры —> <resourceadapter-class>in.fidonode.binkp.ra.BinkpServerResourceAdapter</resourceadapter-class> <config-property> <config-property-name>version</config-property-name> <config-property-type>java.lang.String</config-property-type> <config-property-value>jnode-jee 2.5 binkp/1.1</config-property-value> </config-property> <!— Описание входящего потока —> <inbound-resourceadapter> <messageadapter> <messagelistener> <!— Интерфейс, который должен реализовать @MessageDrivenBean для того, чтоб получать сообщения с этого адаптера —> <messagelistener-type>in.fidonode.binkp.ra.BinkpMessageListener</messagelistener-type> <activationspec> <!— Класс-холдер параметров, которая передается через @ActivationConfigProperty, должны быть доступны геттеры и сеттеры параметров —> <activationspec-class>in.fidonode.binkp.ra.BinkpActivationSpec</activationspec-class> <!— Список обязательных параметров —> <required-config-property> <config-property-name>listenPort</config-property-name> </required-config-property> <!— Описание параметров параметров —> <config-property> <config-property-name>listenPort</config-property-name> <config-property-type>java.lang.Integer</config-property-type> <config-property-value>24554</config-property-value> </config-property> </activationspec> </messagelistener> </messageadapter> </inbound-resourceadapter> </resourceadapter> </connector>

Интерфейс BinkpMessageListener — для клиентов и должен быть в classpath;

Приведу его тут:
public interface BinkpMessageListener { public void onMessage(FidoMessage message); }

Теперь рассмотрим простейшую реализацию ResourceAdapter
BinkpServerResourceAdapter.javapublic class BinkpServerResourceAdapter implements ResourceAdapter, Serializable { private static final long serialVersionUID = 1L; private static Logger log = Logger.getLogger(BinkpServerResourceAdapter.class .getName()); private ConcurrentHashMap<BinkpActivationSpec, BinkpEndpoint> activationMap = new ConcurrentHashMap<BinkpActivationSpec, BinkpEndpoint>(); private BootstrapContext ctx; private String version; @Override public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) throws ResourceException { BinkpEndpoint activation = new BinkpEndpoint(ctx.getWorkManager(), (BinkpActivationSpec) spec, endpointFactory); activationMap.put((BinkpActivationSpec) spec, activation); activation.start(); log.info("endpointActivation(" + activation + ")"); } @Override public void endpointDeactivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) { BinkpEndpoint activation = activationMap.remove(spec); if (activation != null) activation.stop(); log.info("endpointDeactivation(" + activation + ")"); } @Override public void start(BootstrapContext ctx) throws ResourceAdapterInternalException { this.ctx = ctx; log.info("start()"); } @Override public void stop() { for (BinkpEndpoint act : activationMap.values()) { act.stop(); } activationMap.clear(); log.info("stop()"); } @Override public XAResource[] getXAResources(ActivationSpec[] arg0) throws ResourceException { return null; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } }

Что тут происходит? При загрузке JCA-модуля создается экземпляр класса BinkpServerResourceAdapter, у него заполняются параметры ( в данном случае — поле version) и вызывается метод start().
На самом деле, внутри метода start() можно делать много всего, но в данном примере мы просто сохраняем контекст для получения из него в дальнейшем WorkManager’а.

Когда сервер приложений находит @MessageDrivenBean, он пытается найти адаптер, который отправляет сообщения на тот интерфейс, который реализует бин. Для JMS это MessageListener, у нас это BinkpMessageListener. Создается ActivationSpec ( у нас это BinkpActivationSpec, реализующий javax.resource.spi.ActivationSpec), поля в котором заполняются согласно данным в activationConfig, создается MessageEndpointFactory и вызывается ResourceAdapter.endpointActivation(). В этой функции необходимо создать тот «сервер», который будет принимать входящие соединения, будь то tcp/ip сервер или поток для работы с unix-socket, создать на основе того конфига который был в MDB. Класс BinkpEndpoint — это и есть тот самый «сервер».
BinkpEndpoint.javapublic class BinkpEndpoint implements Work, FidoMessageListener { private static final Logger logger = Logger.getLogger(BinkpEndpoint.class .getName()); private BinkpServer server; private final WorkManager workManager; private final MessageEndpointFactory messageEndpointFactory; public BinkpEndpoint(WorkManager workManager, BinkpActivationSpec activationSpec, MessageEndpointFactory messageEndpointFactory) { this.workManager = workManager; this.messageEndpointFactory = messageEndpointFactory; server = new BinkpServer(activationSpec.getListenPort(), this); } public void start() throws ResourceException { workManager.scheduleWork(this); } public void stop() { if (server != null) { server.stop(); } } /** из FidoMessageListener **/ @Override public Message incomingMessage(FidoMessage message) { String message = msg.encode(); BinkpMessageListener listener = (BinkpMessageListener) messageEndpointFactory .createEndpoint(null); listener.onMessage(message); } /** из Work **/ @Override public void run() { server.start(); } /** из Work **/ @Override public void release() { stop(); } }

Можно заметить, что везде фигурируют некие endpoint’ы. У меня был с этим некоторый затык, поэтому расшифрую:
Endpoint — это то, что слушает «входящий» поток. Именно к нему относятся функции endpointActication
MessageEndpoint — экземпляр MDB, который обрабатывает то или иное сообщение. Получается вызовом MessageEndpointFactory.createEndpoint() ( Эту функцию нельзя вызывать из основного треда ). Он легко кастится к интерфейсу MDB.

Собственно, все. Реализацию BinkpServer за ненадобностью опущу, но принцип должен быть понятен, минимальный «Входящий» JCA делается из четырех классов ( ResourceAdapter, MessageListener, ActivationSpec, Endpoint )

Создание Endpoint’а и обработка входящих:
@MessageDriven(messageListenerInterface = BinkpMessageListener.class, activationConfig = { @ActivationConfigProperty(propertyName = "listenPort", propertyValue = "24554") }) public class ReceiveMessageBean implements BinkpMessageListener { @Override public void onMessage(FidoMessage msg) { // do smth with mesaage } }

Исходящие

А вот тут — все веселее, минимальный «Исходящий» JCA делается аж из 8 классов, что в 2 раза больше чем «Входящий». Но давайте по-порядку.

META-INF/ra.xml — описание ResourceAdapter’а и outbound потоков

ra.xml<connector xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/connector_1_7.xsd" version="1.7" metadata-complete="true"> <vendor-name>kreon-services</vendor-name> <eis-type>FidoNet</eis-type> <resourceadapter-version>2.5</resourceadapter-version> <resourceadapter> <!— Класс, который реализует javax.resource.spi.ResourceAdapter; config-property — поля, должны быть доступны через геттеры/сеттеры —> <resourceadapter-class>in.fidonode.binkp.ra.BinkpServerResourceAdapter</resourceadapter-class> <config-property> <config-property-name>version</config-property-name> <config-property-type>java.lang.String</config-property-type> <config-property-value>jnode-jee 2.5 binkp/1.1</config-property-value> </config-property> <!— Описание исходящего потока. Всегда ПЕРЕД входящим —> <outbound-resourceadapter> <connection-definition> <!— Фабрика с которой будет работать JEE-сервер, она создает фабрику для создания соединений —> <managedconnectionfactory-class>in.fidonode.binkp.ra.ManagedConnectionFactory</managedconnectionfactory-class> <!— Фабика соединений, которая будет отдаваться по запросу. Интерфейс должен быть у клиента в classpath —> <connectionfactory-interface>in.fidonode.binkp.ra.ConnectionFactory</connectionfactory-interface> <connectionfactory-impl-class>in.fidonode.binkp.ra.ConnectionFactoryImpl</connectionfactory-impl-class> <!— Соединение, которое будет отдавать фабрика соединений. Интерфейс должен быть у клиента в classpath —> <connection-interface>in.fidonode.binkp.ra.Connection</connection-interface> <connection-impl-class>in.fidonode.binkp.ra.ConnectionImpl</connection-impl-class> </connection-definition> <!— Про транзакции и аутентификацию есть отдельный талмуд, я этот момент пропустил —> <transaction-support>NoTransaction</transaction-support> <reauthentication-support>false</reauthentication-support> </outbound-resourceadapter> <!— Описание входящего потока —> <inbound-resourceadapter> <!— … —> </inbound-resourceadapter> </resourceadapter> </connector>

Интерфейсы Connection и ConnectionFactory — для клиентов и должны быть в classpath. Сразу приведу их тут, там ничего интересного.

BinkpClient приводить не буду 🙂
public interface Connection { public BinkpClient connect(String hostname, int port); } public interface ConnectionFactory { public Connection createConnection(); }

Соединения бывают Managed и Unmanaged. Первые — со свистелками, listener’ами и другим, вторые — без.
Класс, реализующий ManagedConnectionFactory, должен уметь создавать оба типа соединений.
ManagedConnectionFactory.javapublic class ManagedConnectionFactory implements javax.resource.spi.ManagedConnectionFactory { private PrintWriter logwriter; private static final long serialVersionUID = 1L; /** * Создание фабрики для unmanaged-соединений */ @Override public Object createConnectionFactory() throws ResourceException { return new ConnectionFactoryImpl(); } /** * Создание managed-фабрики для managed-connection */ @Override public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException { return new ManagedConnectionFactoryImpl(this, cxManager); } /** * Создание managed-соединения */ @Override public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { return new in.fidonode.binkp.ra.ManagedConnection(); } @Override public PrintWriter getLogWriter() throws ResourceException { return logwriter; } @SuppressWarnings("rawtypes") @Override public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { ManagedConnection result = null; Iterator it = connectionSet.iterator(); while (result == null && it.hasNext()) { ManagedConnection mc = (ManagedConnection) it.next(); if (mc instanceof in.fidonode.binkp.ra.ManagedConnection) { result = mc; } } return result; } @Override public void setLogWriter(PrintWriter out) throws ResourceException { logwriter = out; } }

Когда приложение запрашивает у JEE-сервера тот или иной коннектор, сервер приложений просит ManagedConnectionFactory создать ConnectionFactory и отдает его приложению.

Как можно заметить, ConnectionFactory тоже бывает Managed и Unmanaged. В принципе все это можно свести к одному классу, но это сильно зависит от того, что именно и как мы передаем, есть ли там транзакции итд.
ConnectionFactoryIml просто делает new ConnectionImpl(), а вот ManagedConnectionFactoryImpl чуть посложнее:

ManagedConnectionFactoryImpl.javapublic class ManagedConnectionFactoryImpl implements ConnectionFactory { private ManagedConnectionFactory factory; private ConnectionManager manager; public ManagedConnectionFactoryImpl(ManagedConnectionFactory factory, ConnectionManager manager) { super(); this.factory = factory; this.manager = manager; } /** создает managed-соединение через родителя-ManagedConnectionFactory **/ @Override public Connection createConnection() { try { return (Connection) manager.allocateConnection(factory, null); } catch (ResourceException e) { return null; } } }

ManagedConnection, реализующий javax.resource.spi.ManagedConnection — это обертка для интерфейса Connection, которая как-раз добавляет свистелок и listener’ов. Именно этот класс возвращает ManagedConnectionFactory.createManagedConnection(), которую мы вызываем при создании соединения из ManagedConnectionFactoryImpl.createConnection() через ConnectionManager.allocateConnection()

ManagedConnection.javapublic class ManagedConnection implements javax.resource.spi.ManagedConnection { private PrintWriter logWriter; private Connection connection; private List<ConnectionEventListener> listeners; public ManagedConnection() { listeners = Collections .synchronizedList(new ArrayList<ConnectionEventListener>()); } @Override public void associateConnection(Object connection) throws ResourceException { if (connection != null && connection instanceof Connection) { this.connection = (Connection) connection; } } @Override public Object getConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { if (connection == null) { connection = new ManagedConnectionImpl(); } return connection; } @Override public void cleanup() throws ResourceException { } @Override public void destroy() throws ResourceException { } @Override public PrintWriter getLogWriter() throws ResourceException { return logWriter; } @Override public ManagedConnectionMetaData getMetaData() throws ResourceException { throw new NotSupportedException(); } @Override public XAResource getXAResource() throws ResourceException { throw new NotSupportedException(); } @Override public LocalTransaction getLocalTransaction() throws ResourceException { return null; } @Override public void setLogWriter(PrintWriter out) throws ResourceException { logWriter = out; } @Override public void addConnectionEventListener(ConnectionEventListener listener) { if (listener != null) { listeners.add(listener); } } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { if (listener != null) { listeners.remove(listener); } } }

Ну вот, теперь мы подошли к самому простому — реализации соединения 🙂
public class ConnectionImpl implements Connection { @Override public BinkpClient connect(String hostname, int port) { return new BinkpClient(hostname, port); } }

Итоговая цепочка вызовов для установления исходящего соединения
ManagedConnectionFactory.createConnectionFactory()
->ManagedConnectionFactoryImpl.createConnection()
—>СonnectionManager.allocateConnection()
—>ManagedConnectionFactory.createManagedConnection()
—->ManagedConnection.getConnection()
——>ManagedConnectionImpl.connect()

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

Код для вызова:
private BinkpClient createBinkpClient(String host, int port) { ConnectionFactory cf = ((ConnectionFactory) new InitialContext().lookup("java:eis/BinkpConnectionFactory")); Connection conn = cf.getConnection(); return conn.connect(host, port); }
А причем тут Фидо?

А почти непричем. Дело в том, что изначальная задача была вовсе не о binkp, но она была рабочей, а значит попадала под NDA. Поэтому, разобравшись с JCA и решив что нужно написать статью на Хабре ( кстати, оглядываясь назад я начинаю понимать, почему никто такую статью еще не написал. И это еще без транзакций! ), я разморозил старую идею — форк jnode для JEE-серверов, для запуска ноды в виде одного ear. В свое время именно знаний JCA мне не хватило для того, чтобы запустить проект 🙂

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

Спасибо за внимание, оставайтесь с нами. Опечатки можно писать в комментариях, я даже не сомневаюсь что их тут десятки. http://habrahabr.ru/post/251131/