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

Разработка пользовательского интерфейса (User Interface, UI) — один из наиболее ресурсоемких этапов создания, тестирования и поддержки приложения, поэтому совершенно естественно, что повторное использование компонентов UI столь же важно, как и повторное использование логики приложений [1]. Но, даже несмотря на то, что существуют платформы (такие, как Java Swing), помогающие в современных разработках UI, интеграция отдельных компонентов и, возможно, автономных приложений на уровне UI так и не получила должного внимания.

В этой статье анализируется проблема интеграции графического пользовательского интерфейса, т. е. интеграции компонентов за счет объединения их внешнего представления, а не логики или схем данных самих приложений. В этом случае компонентами являются автономные модули или приложения. Цель заключается в том, чтобы использовать UI отдельных компонентов для создания более функциональных композитных приложений. Необходимость в подобной интеграции очевидна. Приложения, которые накладывают информацию о зданиях на карты Google Maps, приборные панели, ведущие мониторинг различных аспектов производительности компьютерных систем, или операционные Web-среды, которые поддерживают координированные взаимодействия с различными приложениями на одной и той же Web-странице. Все эти примеры требуют координации пользовательских интерфейсов приложений. Увеличение масштаба карты, например, означает, что накладываемая информация о домах, выставленных на продажу, тоже должна измениться.

Уровни интеграции

Для того чтобы описать различные виды интеграции, мы используем простой, но конкретный пример, в основу которого положена разработка реальных приложений в компании Hewlett-Packard. Рассмотрим набор приложений, ведущих мониторинг производительности и качества систем, сетей, сервисов и бизнес-процессов. В рамках этого примера инструментарий системного мониторинга регистрирует параметры (такие, как загрузка центрального процессора) для набора машин и посылает уведомления в том случае, если значения этих параметров превышают определенные пороговые величины, а приложение мониторинга процессов анализирует выполнение бизнес-процессов и сообщает об основных показателях производительности, таких как продолжительность процесса или скорость его реализации. Как и большинство современных приложений, все перечисленные делятся на три уровня: презентация, приложение (также называемое уровнем бизнес-логики) и данные.

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

При интеграции данных [2] композитные приложения имеют свои собственные уровни презентации и приложения, в то время как уровень данных — это интеграция источников данных, которые компонентные приложения могут поддерживать независимо, как это показано на рисунке. В нашем примере различные приложения мониторинга собирают данные в свои локальные хранилища, не зная о том, что они являются объектами интеграции. Уровень интеграции объединяет вместе источники данных и формирует общее, гомогенное представление для композитного приложения. Уровень интеграции может быть физическим или оставаться виртуальным.

При интеграции данных возникает несколько задач, от разрешения несоответствий между моделями данных компонентов (например, когда одни и те же термины имеют разные значения) до создания и поддержки виртуальных схем и установки соответствия запросов между глобальной и локальной схемой. Это требует определенного «сотрудничества» от компонентных приложений: мы всегда можем обратиться к базам данных приложений с помощью SQL-запросов или технологий интеграции информации предприятия (Enterprise Information Integration, EII). Недостаток этого подхода заключается в том, что такое решение требует значительных усилий для того, чтобы разобраться в моделях данных, проанализировать семантические разнородности и поддерживать композитную схему с учетом изменений в схемах данных компонентов [3].

В последние 30 лет выполнено множество исследований в области интеграции приложений, в результате которых были созданы такие технологии, как удаленный вызов процедур, брокеры объектов и Web-сервисы [4]. При интеграции композитное приложение имеет свой собственный пользовательский интерфейс, но уровень бизнес-логики формируется за счет интеграции функций, предоставляемых компонентными приложениями, как показано на рисунке (б). В нашем примере мониторинга приложения могут предоставлять API, которые позволяют клиентам извлекать данные о производительности определенных систем или получать уведомления о случаях снижения этого показателя. Композитное приложение использует эти API для того, чтобы получать информацию, согласовывать ее между различными приложениями мониторинга и отображать консолидированное представление на свой графический пользовательский интерфейс. Когда такое возможно (т. е., когда такие API существуют), эта модель интеграции имеет несколько преимуществ, в том числе:

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

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

Задача интеграции пользовательского интерфейса

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

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

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

Рассмотрим эти четыре аспекта и введем пятый, связанный собственно с задачей интеграции UI.

Компонентная модель

При интеграции приложений компоненты, по существу, характеризуются API и, возможно, компонентной моделью (такой, как в CORBA). При интеграции данных схемы источников данных описывают компоненты, но лишь недавно внешние спецификации стали использоваться при интеграции UI. Действительно, интеграция UI была главным образом предназначена для повторного использования библиотек классов, но выполнение интеграции на уровне презентации тоже требует компонентной модели, которая может поддерживать сложные взаимодействия и координацию. Для каждого отдельного компонента в нашем примере управления, например, мы должны описать:

  • программный интерфейс для компонентов, используемых при интеграции;
  • пользовательский интерфейс компонента, который позволяет с ним взаимодействовать.

Мы можем выделить несколько «степеней интероперабельности», которые допускает пользовательский интерфейс компонента.

Только графический пользовательский интерфейс. Аналогично традиционному монолитному настольному приложению, все взаимодействия с компонентами, поддерживающими коммуникации только на уровне графического пользовательского интерфейса, осуществляются через логику пользовательского интерфейса каждого из компонентов. Единственный способ интегрировать компонентное приложение — это хорошо разобраться в его UI, иметь возможность отслеживать позицию мыши или клавиши, нажимаемые пользователем, и, таким образом, понять, что показывает UI компонента и, возможно, даже выполнять действия, которые вызывают изменения UI (например, создать композитное приложение для того, чтобы имитировать нажатия клавиш мыши или клавиатуры). В этом случае интеграция превращается в очень сложную задачу.

Скрытый интерфейс. Во многих Web-приложениях компонент имеет интерфейс, который дает возможность пользователям контролировать его UI, но для этого интерфейса нет общедоступного описания. При взаимодействии с Web-приложением, например, мы можем получать доступ к контенту и манипулировать им, посылая запросы HTTP и отображая ответы. Такие приложения подчиняются общему протоколу взаимодействия между клиентами (UI) и приложениями, но выяснить формулировку этого протокола может оказаться непросто, поскольку изначально не предполагалось, что он будет программным образом использоваться клиентами.

Опубликованный интерфейс. В этом идеальном случае компонент предоставляет открытое описание своего UI и API для того, чтобы им можно было манипулировать во время исполнения. На низком уровне API может позволить управлять отдельными элементами UI, такими как кнопка или текстовое поле. Высокоуровневый API будет предоставлять набор элементов, т. е. наблюдаемых и управляемых объектов, таких как «система» или «сеть» в случае с мониторингом, а также операции для того, чтобы изменить статус элемента, например, «показать статус системы xyz».

Язык композиции

При интеграции данных композиция часто осуществляется через представления SQL, которые позволяют дизайнерам данных описывать глобальную схему как набор представлений над локальными схемами [2]. При интеграции приложений композиция реализуется либо с помощью языка программирования общего назначения, такого как Java, либо с помощью специализированных языков интеграции приложений, таких как языки композиции потоков работ или сервисов (www.oasis-open.org). Хотя для интеграции UI в этом направлении было сделано мало, мы уверены, что аналогичный подход можно применять и в данном случае. Мы выделяем два вида языков композиции.

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

Специализированные языки композиции. С другой стороны, языки высокого уровня, как правило, используются вместе с синтаксисом XML, адаптированным для композиции компонентов пользовательского интерфейса на уровне абстрактных/внешних описаний. Основное преимущество таких языков — это программирование композиции более высокого уровня, при котором используются характеристики компонентной модели. Если компонентная модель поддерживает, например, понятие элементов, язык композиции будет предоставлять примитивы для работы напрямую с этими концепциями (такие, как изменение отображаемого элемента).

Стиль коммуникаций

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

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

При интеграции UI также можно различать коммуникации через центрального координатора и прямые взаимодействия. В первом случае в композитном приложении есть центральный координатор, который получает события от компонентов и выдает инструкции для манипулирования пользовательскими интерфейсами компонентов. При прямых взаимодействиях между компонентами, когда композитное приложение — это «коалиция» отдельных компонентов, ни одно высокоуровневое приложение эту деятельность не координирует. Следует также отметить еще одно важное различие между взаимодействием в стиле удаленного вызова процедур, при котором компоненты обмениваются информацией с помощью вызовов методов и возврата данных, и взаимодействием по принципу «публикации и подписки» [5], при котором приложения взаимодействуют слабо, обмениваясь сообщениями через брокеров сообщений. В последнем случае брокер распространяет сообщения с учетом контента или темы.

Обнаружение и связывание

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

При интеграции данных и приложений связывание между различными источниками данных, как правило, осуществляется во время проектирования, когда мы определяем глобальную схему данных. Несмотря на то что интеграция программного обеспечения промежуточного слоя поддерживает динамическое обнаружение и связывание [4], эта гибкость, как правило, не используется из-за сложности взаимодействия с вновь обнаруженными компонентами, особенно в тех случаях, когда их предоставляет другая компания (сомнение вызывает их надежность). Во многих случаях приложения перегруппировываются для того, чтобы объединить статическое и динамическое связывание, при котором разработчик приложений определяет и тестирует набор потенциальных компонентов, а пользователь затем выбирает их подмножество во время исполнения, в зависимости от своей задачи. Такое решение называют гибридным связыванием, при котором обнаружение выполняется статически, но мы получаем ссылку во время исполнения. То же самое возможно и при интеграции UI.

Визуализация компонентов

Так кто именно отвечает за отображение компонентов UI? Сам компонент или композитное приложение? В нашем примере с мониторингом мы хотим знать, будут ли компоненты отображать свою собственную панель мониторинга или композитное приложение получает код разметки UI от компонентов и отображает его.

Визуализация разметки требует интерпретации со стороны механизма рендеринга (такого, как браузер или приложение в архитектуре тонкого клиента) для того, чтобы преобразовать описания в графические элементы. Спецификации разметки, как правило, описывают статические свойства UI, в то время как языки скриптов обеспечивают динамические. Кроме того, можно описывать разметку с помощью ориентированных на документы языков (таких как XHTML и Wireless Markup Language [WML; www.openmobilealliance.org]), либо языков UI, которые моделируют сложные интерфейсы приложений (такие, как eXtensible Application Markup Language [XAML; msdn2.microsoft.com]; XML User Interface Language [XUL; www.mozilla.org]; User Interface Markup Language [UIML; www.uiml.org]; eXtensible Interface Markup Language [XIML; www.ximl.org]).

Применительно к визуализации мы выделяем два различных пользовательских интерфейса.

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

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

Технологии композиции UI

В таблице сравниваются различные технологии UI, которые мы рассматриваем в контексте композиции UI.

Компоненты UI настольных приложений

Впервые композиция UI рассматривалась применительно к настольным приложениям. Создание компонентных технологий в конечном итоге привело к появлению среды, в которой приложения, написанные с помощью гетерогенных языков, могут взаимодействовать друг с другом. Типичный тому пример — ActiveX, в котором используется технология Microsoft COM для интеграции полного UI приложения в хостовые приложения. Другими примерами могут служить OpenDoc (developer.apple.com) и Bonobo (developer.gnome.org), которые для поддержки интероперабельности во многом полагаются на базовую операционную систему или компонентное программное обеспечение промежуточного уровня. С другой стороны, Composite UI Application Block (CAB; msdn2.microsoft.com) — это оболочка для композиции UI в Microsoft .Net с помощью контейнерного сервиса, который позволяет разработчикам создавать приложения из загружаемых или подключаемых модулей. Компоненты CAB могут использоваться с любым языком .Net для создания композитных контейнеров и выполнения коммуникаций между компонентами и контейнерами. Затем CAB предоставляет брокер событий для слабосвязанных межкомпонентных коммуникаций «многие ко многим» на основе модели событий времени исполнения, опирающейся на механизм публикации и подписки.

Проект Rich Client Platform (RCP; www.eclipse.org) в рамках Eclipse предоставляет аналогичную платформу, но включает в себя оболочку приложений с такими механизмами UI, как меню и инструментальные панели. Он также предлагает API на базе модулей, которые позволяют разработчикам создавать приложения на основе этой оболочки. Кроме того, Eclipse позволяет разработчикам настраивать и расширять компоненты UI (или подключаемые модули) через так называемые «точки расширения», сочетание Java-интерфейсов и разметок XML, которые определяют интерфейсы компонентов и поддерживают их слабое связывание.

Компоненты UI для настольных приложений, как правило, используют для интеграции компонентов языки программирования общего назначения (например, C# для CAB и Java для RCP), поскольку интерфейсы компонентов — это зависящие от языка API. Компоненты выполняют рендеринг своих UI, и они могут поддерживать гибкие стили связи, в том числе централизованно управляемые коммуникации через посредника или непосредственно между компонентами. Кроме того, поддерживается связывание как во время проектирования, так и во время исполнения, причем в последнем случае используются механизмы установки соответствия, специфические для данного языка.

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

Подключаемые компоненты в браузере

При использовании интерфейсов на базе разметки можно реализовать разнообразные возможности UI с помощью встроенных компонентов UI, таких как апплеты Java, элементы управления ActiveX и Macromedia Flash.

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

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

Web-коллажи

Коллажи (mashup) в Web — это Web-ресурсы, которые упаковывают и повторно используют сторонний Web-контент. Первые коллажи не могли использовать API, поскольку поставщики оригинального контента даже не знали о том, что их Web-сайты используются в других приложениях. Например, в Google Maps первые коллажи появились еще до официального выпуска Google Maps API. Создание этих API стало ответом Google на все большее число случаев нелегитимной интеграции своих карт, когда разработчики соответствующих приложений загружали весь код AJAX для карт и получали необходимую функциональность.

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

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

Web-порталы и портлеты

Разработка Web-порталов четко разделяется на компоненты UI (портлеты) и композитные приложения (порталы) и, по-видимому, сейчас является самым передовым подходом к композиции UI (термин «портлеты» появился от Java Portlet, но впоследствии о портлетах стали говорить и применительно к ASP.Net Web Parts). Портлеты — это полнофункциональные подключаемые компоненты Web-приложений. Они генерируют фрагменты разметки документов, которые подчиняются определенным правилам, тем самым поддерживают агрегацию контента в портальных серверах для того, чтобы в конечном итоге формировать композитные документы.

Аналогично Java-сервлетам портлеты реализуют конкретный Java-интерфейс для стандартного API портлетов, который, как предполагалось, должен помочь разработчикам создавать портлеты, способные подключаться к любому удовлетворяющему стандартам портальному серверу. Например, JSR-168 определяет среду времени исполнения для портлетов и Java API. Что касается Java-портлетов, то портальные приложения базируются на языке программирования Java, в то время как в случае с Web Parts разработчик Web создает приложения в .Net. Портальное приложение объединяет разметки своих портлетов и управляет коммуникациями через механизм центрального координатора. Кроме того, портлеты поддерживают как статическое, так и динамическое связывание. Во время исполнения портальное приложение может предоставлять доступ к портлетам и реестру, где пользователи могут их выбирать и позиционировать.

JSR-168 не предоставляет механизм коммуникаций между портлетами, но сейчас в этой области ведутся активные исследования. Web Parts поддерживают коммуникации между компонентами с помощью разделяемых структур данных, но в силу этого Web Parts тесно связаны друг с другом, — возможно, более подходящим здесь был бы механизм поддержки событий на основе технологии публикации и подписки.

Несмотря на то что портлеты и Web Parts имеют сходные цели и архитектуры, они не поддерживают интероперабельность друг с другом. Web Services for Remote Portlets (WSRP; www.oasis-open.org) решает эту проблему на уровне протокола за счет предоставления удаленных портлетов в виде Web-сервисов, а коммуникации между портальным сервером (потребитель WSRP) и портлетами (производитель WSRP) осуществляются через SOAP. Это означает, что разработчики могут создавать портал и портлеты с помощью различных языков и оболочек времени исполнения. WSRP 1.0 не поддерживает коммуникации между портлетами, но в WSRP 2.0 будет предложен механизм распространения событий.

***

Интеграция UI начнет широко применяться только после проведения эффективной стандартизации, аналогичной стандартизации сервисных интерфейсов.

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

Литература

  1. B.A. Myers, M.B. Rosson, Survey on User Interface Programming. Proc. SIGCHI Conf. Human Factors in Computing Systems, ACM Press, 1992.
  2. M. Lenzerini, Data Integration: A Theoretical Perspective. Proc. 21st ACM SIGMOD-SIGACT-SIGART Symp. Principles of Database Systems, ACM Press, 2002.
  3. A. Halevy et al., Enterprise Information Integration: Successes, Challenges and Controversies. Proc. 2005 ACM SIGMOD Intl Conf. Management of Data, ACM Press, 2005.
  4. G. Alonso et al., Web Services: Concepts, Architectures, and Applications. Springer, 2004.
  5. P.T. Eugster et al., The Many Faces of Publish/Subscribe. ACM Computing Surveys, vol. 35, no. 2, 2003.
  6. J. Yu et al., A Framework for Rapid Integration of Presentation Components. To be published in Proc. 16th Int’l World Wide Web Conf., ACM Press, 2007.

Флориан Дениэль (daniel@elet.polimi.it) и Мариселла Матера (matera@elet.polimi.it) — сотрудники Политехнического университета Милана (Италия). Джин Ю (jyu@cse.unsw.edu.au) и Реджис Сен-Поль (regiss@cse.unsw.edu.au) — сотрудники Университета Южного Уэльса (Австралия). Булем Бенаталлах (boualem@cse.unsw.edu.au) — доцент Университета Южного Уэльса (Австралия). Фабио Касати (casati@dit.unitn.it) — профессор Университета Тренто (Италия).


Florian Daniel, Maristella Matera, Jin Yu, Boualem Benatallah, Regis Saint-Paul, Fabio Casati. Understanding UI Integration. A Survey of Problems, Technologies, and Opportunities. IEEE Internet Computing, May/June 2007. IEEE Computer Society, 2007. All rights reserved. Reprinted with permission.

Поделитесь материалом с коллегами и друзьями