Найдено на: http://www.i-rs.ru/article/articleprint/434/-1/55/
|
Главная
OpenOffice.org
Статьи и переводы
Конкурс на лучшую статью
Конкурсные работы (53)
Об этом уже писали (5)
Начала программирования в OpenOffice.org
|
Недолго думая, я решил заполнить прискорбную пустоту в документации ООо, а именно - нехватку ПЕРВИЧНОЙ документации, и перевел главу из Developer Guide, а именно, вторую главу, под названием First Steps.
Строго дословного перевода не получилось, пришлось кое-где править листинги, вносить изменения в текст - тем не менее, перевод ПРАКТИЧЕСКИ дословный, и, в то же время, "литературно" обработан.
Если этот перевод станет началом проекта по переводу всей документации ООо - будет счастье.
Содержание
-
Программирование в UNO
-
Области приложения UNO
-
С чего начать
-
Как получить объекты OpenOffice.org
-
Работа с объектами
-
Как определить тип полученного объекта
-
Пример: работа с текстом, таблицей и фигурой
-
Пример приложения
Программирование в UNO
Основной технологией OpenOffice.org выступает UNO (Universal Network Objects – Универсальные Сетевые Объекты). Эта технология позволяет использовать и создавать компоненты, работающие независимо от языка программирования, компонентной технологии, компьютерной платформы и типа используемой сети. В настоящее время варианты UNO доступны для Linux, Solaris, Power PC, Windows, FreeBSD и Mac OS X, поддерживаются языки Java, C++ и OpenOffice.org Basic. Другие порты – на стадии разработки. Через компонентную технология MS COM UNO доступно для многих других языков, в OpenOffice.org есть привязка к Python.
Возможно программирование для OpenOffice.org UNO с использованием .NET языков, при помощи CLI (Common Language Infrastructure – Общая Инфраструктура Языков), и с применением сценарных языков, таких, как JavaScript, Beanshell или Jython.
Для доступа к OpenOffice.org UNO использует API (Application Programming Interface – Интерфейс Прикладного Программирования) OpenOffice.org.
Области приложения UNO
При помощи UNO можно соединиться с локальным или удаленным экземпляром OpenOffice.org при помощи C++, Java, COM/DCOM C++ и Java десктоп-приложений, сервлетов Java, Java Server Pages, JScript, VBScript и языков наподобие Delphi, Visual Basic и многих других.
На C++ или Java можно разработать компоненты UNO, экземпляры которых будут создаваться OpenOffice.org и добавлять к офисным приложениям новые возможности. Например, можно написать Add-in-ы для Chart, Calc, лингвистические расширения, файловые фильтры, драйверы баз данных. Можно создавать и завершенные, полнофункциональные приложения, в том числе и для групповой работы.
Компоненты UNO (как и, к примеру, Java Beans) объединяются с Java IDE, что облегчает доступ к OpenOffice.org .В настоящее время разрабатывается набор таких компонентов, которые позволят редактировать документы OpenOffice.org в приложениях Java.
OpenOffice.org Basic связан с UNO так, что программы UNO могут быть написаны непосредственно в OpenOffice.org . Используя этот способ, можно создавать собственные офисные решения и мастера, основанные на событийно-управляемой диалоговой парадигме.
Ядро управления базами данных, встроенное в OpenOffice.org и связанные с базами данных компоненты открывают область решений, управляемых базами данных.
С чего начать
Для работы с OpenOffice.org API следует установить некоторые пакеты.
Требующиеся файлы
-
Прежде всего, очевидно, надо установить экземпляр OpenOffice.org . Его можно скачать с сайта www.openoffice.org.
-
Справочная информация по OpenOffice.org API является частью пакета разработчика OpenOffice.org SDK (Software Development KIT – Набор для Разработки Программного обеспечения). Справочник по OpenOffice.org API можно загрузить с api.openoffice.org
Установочные пакеты
Для разработки приложений OpenOffice.org на Java следует установить:
-
Java Development Kit – Набор для Разработки на Java версии 1.3.1 или более новый. JDK доступен на сайте java.sun.com. Для использования всех возможностей OpenOffice.org нужна версия Java не старше 1.4.1_01.
-
Java IDE, такая, как NetBeans или подобная. (Рекомендуем интегрированную с OOo IDE Eclipe. Комментарий Infra)
-
OpenOffice.org SDK, который можно загрузить с www.openoffice.org.
Конфигурация
Подключение Java к OpenOffice.org
Для создания экземпляров компонентов, написанных на Java, OpenOffice.org использует Java Virtual Machine. Начиная с версии OpenOffice.org 2.0 Java запускается автоматически при запуске офисного приложения – или позднее, при необходимости. Если требуется заранее выбрать JDK или JRE из имеющихся на компьютере, или если Java не установлена – можно произвести конфигурирование Java, используя диалоговое окно, доступное из меню Сервис->Параметры, в секции OpenOffice.org->Java. В более ранних версиях OpenOffice.org следует использовать утилиту jvmsetup, после чего перезапустить OpenOffice.org.
Использование файлов классов Java UNO
Расположение классов OpenOffice.org должно быть сообщено Java IDE. А именно, к проекту Java следует подключить пакеты jurt.jar, unoil.jar, ridl.jar и juh.jar, которые находятся в каталоге [путь_к_OpenOffice.org]/program/classes. Кроме того, следует добавить папки [путь_к_OpenOffice.org_SDK]/docs/common/ref и [путь_к_OpenOffice.org_SDK]/docs/java/re к пути поиска документации Javadoc – конкретные шаги зависят от используемой IDE. Это позволит легко использовать справочник OpenOffice.org API при работе.
Первый контакт
Начинаем
Начиная с версии OpenOffice.org 2.0 стало просто получить рабочее окружение для прозрачного использования функциональности UNO и самого OpenOffice.org .В данном примере показано, как написать маленькую программу, инициализирующую UNO. Эта программа соединяется с экземпляром офиса или запускает экземпляр – если офис не был запущен, и сообщает о возможности получить контекст экземпляра офиса, обеспечиваемый объектом офисного менеджера сервисов.
-
Создайте файл FirstUnoContact.java и внесите код примера.
-
Не забудьте добавить к проекту jar-файлы, как описано выше.
Для упрощения компиляции можно добавить к проекту ant-файл
Конечно же, переменные OFFICE_HOME, OOO_SDK_HOME и OUTDIR в ant-файле придется изменить соответственно тому, что имеется на вашей машине.
Теперь разберем, что происходит при выполнении кода.
Менеджеры сервисов
UNO вводит концепцию менеджеров сервисов, которые являются объектами-"фабриками", создающими сервисы. Сервис, в свою очередь, – объект UNO, выполняющий те или иные задачи (подробнее – позднее).
Например, очень часто применяются следующие сервисы:
Сервис всегда существует в компонентном контексте, включающем менеджер сервисов, который создает сервис, и другие данные, используемые сервисом.
В приведенном примере экземпляр класса FirstUnoContact – клиент процесса OpenOffice.org, сам же OpenOffice.org – сервер. Сервер имеет собственные компонентный контекст и менеджер сервисов, к которым может обратиться клиент, чтобы воспользоваться функциональностью офиса.
Клиентская программа инициализирует UNO и получает компонентный контекст от процесса OpenOffice.org.
Говоря подробнее, инициализирующий процесс создает локальный менеджер сервисов, устанавливает канальное подключение с выполняющимся процессом OpenOffice.org, при необходимости создавая новый процесс, и возвращает удаленный компонентный контекст.
Метод com.sun.star.comp.helper.Bootstrap.bootstrap() инициализирует UNO и возвращает удаленный компонентный контекст выполняющегося процесса OpenOffice.org.
После этого можно использовать метод getServiceManager() компонентного контекста для получения удаленного менеджера сервисов от процесса OpenOffice.org, что позволяет работать с функциональностью офиса, доступной через API.
Нарушение подключения
Иногда удаленное подключение может не установиться, либо утратиться в процессе работы.
-
Клиент должен быть способен обнаружить ошибки. Например, иногда мост может быть недоступен. Простые клиенты, соединяющиеся с офисом, выполняющие некоторую задачу и прекращающие работу, должны выполнить остановку и сообщить пользователю об ошибке соединения.
-
Клиенты, предполагающие длительную работу, не должны предполагать, что ссылка на начальный объект будет существовать все время работы. Клиент должен возобновлять подключение при разрыве и продолжать работу. Когда подключение прерывается, длительно работающий клиент должен приостановить текущую задачу, сообщить пользователю о том, что подключение не доступно и высвободить ссылку на удаленный процесс. Если пользователь пытается повторить последнее действие, клиент должен попытаться восстановить подключение. Не следует строить программу так, чтобы ее надо было перезапускать только потому, что подключение было временно недоступно.
При попытке обращения к мосту, в настоящее время недоступному, возникает исключение com.sum.star.lang.DisposedException. Всегда, когда в программе производится обращение к удаленные ссылкам, следует отлавливать это исключение, при возникновении его обнулять удаленные ссылки и оповещать пользователя. Если клиент работает в течение некоторого времени, следует получать новые удаленные ссылки всякий раз, когда они оказываются обнулены.
Более сложный способ поддерживать утраченные подключения – регистрация слушателя объекта моста.
Как получить объекты OpenOffice.org
Объект – это программный артефакт, имеющий методы, которые можно вызывать. Объекты делают что-то с OpenOffice.org. Рассмотрим способы их получения.
Новые объекты
Вообще новые объекты – или объекты, нужные для начального доступа, – создаются менеджерами сервисов OpenOffice.org. В примере FirstLoadComponent (он будет рассмотрен ниже) удаленный менеджер сервисов создает удаленный объект Desktop, управляющий окнами приложений и загружающий документы в OpenOffice.org.
Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop",xRemoteContext); |
Объекты документов
Объекты документов представлены файлами, открытыми в OpenOffice.org. Они создаются объектом Desktop, использующим для этого метод loadComponentFromURL().
Объекты, предоставляющие другие объекты
Объекты могут предоставлять другие объекты двумя основными способами.
-
Атрибуты, спроектированные как неотъемлемая часть другого объекта, могут быть получены get-методами. Например, метод getSheets() необходим для каждого документа Calc, getText() для каждого документа Writer и т.д. После загрузки документа эти методы могут использоваться для получения листов (Sheets) и текста (Text) соответствующих документов. Объекто-специфические get-методы – важная техника получения объектов.
-
Атрибуты, не являющиеся неотъемлемой частью архитектуры других объектов, доступны через набор стандартных методов. В OpenOffice.org API эти атрибуты называются свойствами, для обращения к ним используются общие методы, такие, как getPropertyValue(String propertyName), Иногда такие не-неотъемлемые атрибуты представляются как объекты и, таким образом, метод getPropertyValue() может быть еще одним источником объектов. Например, стили страниц (для электронных таблиц) имеют свойства RightPageHeaderContent и LeftPageHeaderContent, содержащие объекты колонтитулов страниц.
Наборы объектов
Объекты могут быть членами набора однообразных объектов. Чтобы обратиться к объекту-члену набора, следует знать, как производится доступ к элементу набора. OpenOffice.org API предоставляет четыре способы получения элемента из набора. Первые три – объекты с методами обращения к элементу по имени, индексу или перечислению. Четвертый путь – последовательность элементов, не имеющая методов доступа, а используемая как массив.
Выбор способа получения элемента определяется проектировщиком применительно к данной конкретной ситуации.
Работа с объектами
Объекты, интерфейсы и сервисы
Объекты
В UNO объект – программный артефакт, имеющий методы, которые можно вызывать и атрибуты, которые можно получать и устанавливать. Конкретный набор методов и атрибутов, предоставляемых объектом, определяется интерфейсами, реализуемыми объектом.
Интерфейсы
Интерфейс описывает набор атрибутов и методов, которые вместе определяют некоторый единичный аспект объекта. Например, интерфейс
com.sun.star.resource.XResourceBundle:
module com
{
module sun
{
module star
{
module resource
{
interface XResourceBundle: com::sun::star::container::XNameAccess
{
[attribute] XResourceBundle Parent;
com::sun::star::lang::Locale getLocale();
any getDirectElement([in] string key);
};
};
};
};
}; |
определяет атрибут Parent и методы getLocale() и getDirectElement().
Для обеспечения многократного использования подобных интерфейсных спецификаций, интерфейс может наследовать один или более других интерфейсов (например, XResourceBundle наследует все атрибуты и методы интерфейса com.sun.star.container.XNameAccess). Множественное наследование интерфейсов – новая возможность OpenOffice.org 2.0.
Строго говоря, интерфейсные атрибуты не необходимы в UNO. Каждый атрибут может быть представлен сочетанием get-метода для получения значения атрибута и set-метода для установки значения (или одного из этих методов). Но с использованием атрибутов возможно лучше выразить нюансы особенностей объекта. Атрибуты могут использоваться для не неотъемлемых особенностей объекта, а методы доступа резервируются для манипуляции с необходимыми аспектами объектов.
Исторически типичный объект UNO поддерживал набор из нескольких независимых интерфейсов, соответствующих различным ракурсам объекта. С множественным наследованием ситуация изменилась, объект может поддерживать один интерфейс, наследующий все остальные.
Сервисы
Изначально используемый в UNO термин "сервис" был не вполне ясен. Начиная с версии OpenOffice.org 2.0 ситуация прояснилась, но до сих пор остаются разночтения для термина "сервис". В дальнейшем будет использоваться термин в новом значении, соответствующем разъясненной концепции OpenOffice.org 2.0. Словосочетание "сервис старого стиля" будет применяться для обозначения объекта, соответствующего старой, неопределенной концепции. Затрудняет ситуацию и то, что слово "сервис" применяется и помимо UNO в самых разных значениях.
Хотя сейчас нет надобности в сервисах старого стиля, OpenOffice.org API продолжает поддерживать их для сохранения обратной совместимости.
Сервис "нового стиля" выглядит так:
module com
{
module sun
{
module star
{
module bridge
{
service UnoUrlResolver: XUnoUrlResolver;
};
};
};
}; |
Это определяет, что объекты, поддерживающие некоторый интерфейс (например, здесь com.sun.star.bridge.XUnoUrlResolver) будут доступны под некоторым именем сервиса – здесь com.sun.star.bridge.UnoUrlResolver, – в компонентном контексте менеджера сервисов. Иначе сервисы "нового стиля" еще называют сервисами, основанными на одиночном интерфейсе.
Сервис старого стиля – иначе называемый накопительным сервисом, – выглядит так:
module com
{
module sun
{
module star
{
module frame
{
service Desktop
{
service Frame;
interface XDesktop;
interface XComponentLoader;
interface com::sun::star::document::XEventBroadcaster;
};
};
};
};
}; |
В общем, если объект определен как поддерживающий какой-то сервис старого стиля, то следует ожидать, что этот объект будет поддерживать все интерфейсы, экспортируемые этим сервисом – и всеми унаследованными сервисами.
Например, метод com.sun.star.frame.XFrames.queryFrames() вернет последовательность объектов, все они будут поддерживать сервис старого стиля com.sun.star.frame.Frame, и, следовательно, все интерфейсы, экспортируемые Frame.
Сервис старого стиля может содержать одно (или более) свойств:
module com
{
module sun
{
module star
{
module frame
{
service Frame
{
interface com::sun::star::frame::XFrame;
interface com::sun::star::frame::XDispatchProvider;
// ...
[property] string Title;
[property, optional] XDispatchRecorderSupplier RecorderSupplier;
// ...
};
};
};
};
}; |
Свойства (подробнее рассматриваемые ниже) подобны интерфейсным атрибутам, и описывают некоторые дополнительные особенности объекта. Основное отличие от атрибутов – обращение к атрибутам производится непосредственно, тогда как к свойствам сервисы старого стиля обращаются при помощи родовых интерфейсов, таких, как com.sun.star.beans.XPropertySet. Интерфейсные атрибуты чаще применяются для представления неотъемлемых особенностей объектов, тогда как свойства определяют дополнительные, более изменчивые аспекты.
Некоторые сервисы старого стиля подразумевают доступность в компонентном контексте менеджера сервисов. Например, экземпляр сервиса com.sun.star.frame.Desktop может быть создан в компонентном контексте менеджера сервисов под собственным именем "com.sun.star.frame.Desktop". Но нельзя определить, предназначен ли какой-то сервис старого стиля для подобного использования, тогда как применение сервиса "нового стиля" делает намерение подобного использования более прозрачным.
Другие сервисы старого стиля проектируются как родовые "супер-сервисы", предназначенные для наследования другими сервисами. Например, сервис com.sun.star.document.OfficeDocument служит родовой основой для многих конкретных сервисов документа, таких, как com.sun.star.text.TextDocument, или com.sun.star.drawing.DrawingDocument. Для определения подобных базовых родовых сервисов предпочтителен механизм множественного наследования.
Другие сервисы старого стиля проектируются как родовые "супер-сервисы", предназначенные для наследования другими сервисами. Например, сервис com.sun.star.document.OfficeDocument служит родовой основой для многих конкретных сервисов документа, таких, как com.sun.star.text.TextDocument, или com.sun.star.drawing.DrawingDocument. Для определения подобных базовых родовых сервисов предпочтителен механизм множественного наследования.
Другие сервисы старого стиля лишь перечисляют свойства, не экспортируя каких-либо интерфейсов. Подобные сервисы используются для описания набора связанных между собою свойств. Например, сервис com.sun.star.document.MediaDescriptor перечисляет все свойства, которые могут быть переданы методу интерфейса
com.sun.star.frame.XComponentLoader.loadComponentFromURL.
Свойства определяют такие аспекты объекта, которые не являются его неотъемлемой или структурной частью, и поэтому обрабатываются при помощи родовых методов getPropertyValue() и setPropertyValue() вместо специализированных методов, наподобие getPrinter(). Сервисами старого стиля предлагается специальный синтаксис для перечисления свойств объекта. Объект, содержащий свойства, должен поддерживать интерфейс com.sun.star.beans.XPropertySet, что дает возможность работать со всеми разновидностями свойств. Например – свойства, содержащие какие-то параметры форматирования символа или абзаца. При помощи свойств можно определить несколько параметров одним вызовом метода setPropertyValues(), что весьма повышает производительность при удаленной работе. К примеру, объекты-абзацы поддерживают метод setPropertyValues() благодаря реализуемому ими интерфейсу
com.sun.star.beans.XMultiPropertySet.
Использование сервисов
Причины появления концепций интерфейсов и сервисов.
-
Интерфейсы и сервисы отделяют спецификацию от реализации.
Спецификация интерфейса или сервиса абстрактна, то есть не определяет, как объект, обеспечивающий некую функциональность, делает это. Благодаря этому можно менять реализацию компонентов, не изменяя другие части программы.
-
Сервисы позволяют создавать экземпляры по имени спецификации – не по имени класса.
В языках Java или C++ для создания экземпляра класса используется оператор new. При таком подходе получаемый класс жестко предопределен, нельзя создать экземпляр другого класса без изменения кода. Применение сервисов решает эту проблему. Глобальный менеджер сервисов (центральную "фабрику" объектов OpenOffice.org) клиенты запрашивают создать объект для какой-то цели – без какого-то указания на внутреннюю реализацию запрашиваемого объекта. Это возможно потому, что создание сервиса запрашивается согласно имени сервиса, и уже менеджер сервисов ("фабрика" объектов) будет решать, какую именно реализацию сервиса создавать. Для клиента нет разницы, какую реализацию он получил, если полученный объект поддерживает нужные интерфейсы.
-
Множественное наследование облегчает управление малоразмерными интерфейсами.
Абстрактные интерфейсы проще повторно использовать, если они малоразмерны – то есть если они малы по размерам и описывают только какую-то один аспект объекта. В таком случае требуется много подобных интерфейсов для описания большого объекта. Множественное наследование упрощает задачу манипулирования большим количеством малоразмерных интерфейсов.
Рассмотрим сервис старого стиля com.sun.star.text.TextDocument в нотации UML.
Как видно, здесь схематически изображены сервисы com.sun.star.text.TextDocument и com.sun.star.document.OfficeDocument.
Также видно, какие интерфейсы экспортирует каждый из этих сервисов. В OpenOffice.org API принято начинать имя интерфейса с буквы X.
Каждый объект TextDocument должен поддерживать интерфейсы XTextDocument, XSearchable и XRefreshable. Так как TextDocument наследует OfficeDocument, он также поддерживает XPrintable, XStorable, XModel и XModifiable. Методы этих интерфейсов обеспечивают различные аспекты поведения объекта, как видно из названия: печать, сохранение, модификацию, управление моделью и др.
Не следует забывать, что на схеме отображены лишь основные интерфейсы. Реальное устройство объектов намного сложнее.
Использование интерфейсов
Обращение к объектам UNO через его интерфейсы накладывает особенность при кодировании на Java или C++. В этих языках компилятор нуждается в правильном типе ссылки для того, чтобы можно было вызывать методы объекта, и обычно перед обращением к интерфейсу следует произвести приведение типа. При работе с объектами UNO дело обстоит иначе. Следует запросить UNO о соответствующей ссылке каждый раз, когда производится обращение к методам интерфейса, поддерживаемого объектом.
Для этого существует метод UNO queryInterface(). Это выглядит довольно усложненно, но позволяет безопасное (в том числе межпроцессное) приведение типов. В примере FirstloadComponent создается новый объект Desktop, и метод queryInterface() используется для получения ссылки на интерфейс XComponentLoader.
Object desktop = xRemoteServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", xRemoteContext);
XComponentLoader xComponentLoader = (XComponentLoader)
UnoRuntime.queryInterface(XComponentLoader.class, desktop); |
Здесь делается запрос методу менеджера сервисов (объект xRemoteServiceManager) createInstanceWithContext() для создания экземпляра com.sun.star.frame.Desktop. Этот метод возвращает Java-тип Object, на самом же деле этот объект типа com.sun.star.frame.Desktop.
Вот спецификация этого метода:
java.lang.Object createInstanceWithContext(String serviceName, XComponentContext context) |
Далее создается ссылка на интерфейс XComponentLoader объекта desktop. Хотя мы и знаем, что этот объект экспортирует требуемый интерфейс, компилятор не имеет информации об этом. Поэтому делается запрос методом UNO queryInterface() чтобы получить ссылку требуемого типа. При этом для компилятора нет разницы, локальный или удаленный объект используется.
В языке Java есть два вида спецификации этого метода:
java.lang.Object UnoRuntime.queryInterface(java.lang.Class targetInterface, Object sourceObject)
java.lang.Object UnoRuntime.queryInterface(com.sun.star.uno.Type targetInterface, Object sourceObject) |
Так как метод queryInterface() возвращает значение типа java.lang.Object, следует все же принудительно привести тип. Однако (в отличие от метода createInstanceWithContext()) здесь можно безопасно приводить тип, и ссылка будет работать – даже с объектом другого процесса.
Еще раз подробно разберем запрос интерфейса.
XComponentLoader xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, desktop); |
XComponentLoader – тип интерфейса, который мы хотим использовать, для чего создаем переменную по имени xComponentLoader. В ней будет храниться результат запроса к queryInterface().
Аргументы здесь – требуемый интерфейс XComponentLoader.class и объект desktop, у которого этот интерфейс запрашивается.
Перед присвоением значения происходит приведение типа результата к типу XComponentLoader. Если объект не поддерживает запрашиваемый интерфейс, метод вернет null.
В Java подобный запрос делается каждый раз, когда нужна ссылка на объект, поддерживающий нужный интерфейс. Можно сделать запрос интерфейса не только от объекта, но и от другой интерфейсной ссылки:
// загружаем пустой документ, полученный при помощи интерфейса XComponent:
XComponent xComponent = xComponentLoader.loadComponentFromURL("private:factory/scalc", "_blank", 0, loadProps);
//а теперь запрашиваем ссылку на XSpreadsheetDocument:
XSpreadsheetDocument xSpreadsheetDocument =
(XSpreadsheetDocument)UnoRuntime.queryInterface(XSpreadsheetDocument.class, xComponent); |
Если метод определен так, что сразу возвращает интерфейсный тип – нет нужды в запросе интерфейса, можно сразу использовать его методы.
В приведенном выше отрывке метод loadComponentFromURL() определен так, что возвращает интерфейсный тип com.sun.star.lang.XComponent – и можно сразу вызывать методы addEventListener() и removeEventListener(), используя переменную xComponent – если нужно получать уведомление о закрытии документа.
Вот так это делается в C++:
//получаем экземпляр сервиса от менеждера сервисов
Reference < XInterface > rInstance =
rServiceManager->createInstanceWithContext(
OUString::createFromAscii("com.sun.star.frame.Desktop" ),
rComponentContext );
//запрос интерфейса XComponentLoader
Reference < XComponentLoader > rComponentLoader( rInstance, UNO_QUERY ); |
В OpenOffice.org Basic нет необходимости в запросе интерфейсов, Basic делает это самостоятельно.
С увеличением числа множественно-унаследованных интерфейсов уменьшается число запросов интерфейсов в Java и C++.
Предположим, есть интерфейсы:
interface XBase1 {
void fun1();
};
interface XBase2 {
void fun2();
};
interface XBoth { // наследует оба интерфейса: XBase1 и XBase2
interface XBase1;
interface XBase2;
};
interface XFactory {
XBoth getBoth();
}; |
Используя интерфейс, полученный при помощи XFactory.getBoth(), поддерживает методы fun1() и fun2() одновременно, нет надобности создавать ссылки на интерфейсы XBase1 и XBase2.
Использование свойств
Объект предлагает клиенту свойства при помощи интерфейсов, которые позволяют работать со свойствами. Основной интерфейс, используемый для этого – com.sun.star.beans.XPropertySet. Есть и другие интерфейсы, такие, как com.sun.star.beans.XMultiPropertySet, работающий с несколькими свойствами путем одиночного вызова метода. XPropertySet поддерживается всегда, если у сервиса есть свойства.
Два метода XPropertySet осуществляют доступ к свойству. Определение методов в Java таково:
void setPropertyValue(String propertyName, Object propertyValue)
Object getPropertyValue(String propertyName) |
Пример: работа с электронной таблицей
В примере FirstLoadComponent интерфейс XPropertySet используется для установки свойства CellStyle объекта ячейки Объект ячейки – экземпляр com.sun.star.sheet.SheetCell, и поэтому поддерживает сервис com.sun.star.table.CellProperties, который имеет свойство CellStyle.
//запрос к интерфейсу XPropertySet объекта ячейки
XPropertySet xCellProps = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class, xCell);
//установка значения свойства CellStyle
xCellProps.setPropertyValue("CellStyle", "Result"); |
В примере FirstLoadComponent мы делаем запрос удаленному менеджеру сервисов для получения удаленного объекта Desktop и используем метод loadComponentFromURL() для создания нового документа-электронной таблицы. В этом документе мы получаем контейнер листов таблицы и осуществляем доступ к новому листу по имени. В новом листе мы вводим значения в ячейки A1 и A2, суммируя их в ячейке A3. Ячейка-результат получает стиль Result – подчеркнутый полужирный курсив. Наконец, этот лист делается активным – чтобы с ним мог работать пользователь.
Общие типы
До сих пор литеральные и общие типы для параметров методов и возвращаемых значений использовались нами так, будто бы OpenOffice.org API написан специально для Java. Однако следует помнить, что UNO задуман как независимый язык и имеет собственный набор типов, которые следует как-то соотносить с типами используемого языка.
Основные типы
Основные типы UNO обычно выступают типами членов структур, параметров и возвращаемых значений методов. Вот сводная таблица основных типов OpenOffice.org UNO:
Строки
UNO считает строки простыми типами, но в некоторых языках они обрабатываются особым образом.
Java обрабатывает строки как объекты java.lang.String.
В C++ символьные строки должны быть преобразованы в UNO-строки Unicode с помощью функций преобразования, обычно – функции createFromAscii() в объект класса rtl::OUString:
//C++
static OUString createFromAscii(const sal_Char * value) throw(); |
OpenOffice.org Basic работает со строками без дополнительных преобразований.
Перечисления и группы констант
В OpenOffice.org API используются типы перечисления (enum) и группы констант. Перечисления используются для создания списков допустимых в данном контексте именованных значений. Группы констант определяют допустимые значения для свойств, параметров, возвращаемых значений и членов структур.
Например, перечисление com.sun.star.table.CellVertJustify описывает допустимые значения вертикального выравнивания содержимого ячейки таблицы. За вертикальное выравнивание ячейки таблицы отвечает свойство com.sun.star.table.CellProperties.VertJustify. Допустимые значения этого свойства, согласно перечислению CellVertJustify – STANDARD, TOP, CENTER и BOTTOM.
//выравнивание содержимого ячейки по верхней границе ячейки.
//
//сервис com.sun.star.table.Cell включает в себя сервис com.sun.star.table.CellProperties
//и имеет свойство VertJustify, управляющее вертикальным выравниванием.
//для установки свойства используем интерфейс XPropertySet
xCellProps.setPropertyValue("VertJustify", com.sun.star.table.CellVertJustify.TOP); |
OpenOffice.org Basic может использовать перечисления и группы констант напрямую:
oCellProps.VertJustify = com.sun.star.table.CellVertJustify.TOP
|
В C++ эти типы используются так:
rCellProps->setPropertyValue(OUString::createFromAscii( "VertJustify" ),
::com::sun::star::table::CellVertJustify.TOP); |
Структуры
Структуры в OpenOffice.org API используются для создания составных типов из уже существующих. Структуры OpenOffice.org соответствуют структурам C++ или Java-классам, содержащим только публичные члены.
Структуры не инкапсулируют данные, они упрощаю передачу данных "целиком", вместо выстраивания ряда запросов get/set. Это дает преимущества, к примеру, при связи с удаленными компонентами.
Доступ к членам структур производится оператором-точкой ".", например:
aProperty.Name = "ReadOnly"; |
В Java, C++ и Basic при создании экземпляра структуры используется слово new. Применяя автоматизацию OLE (ActiveX), для получения экземпляра структуры следует использовать com.sun.star.reflection.CoreReflection. Для создания структур не следует применять менеджер сервисов. Например:
//В Java:
com.sun.star.beans.PropertyValue aProperty = new com.sun.star.beans.PropertyValue(); |
'В Basic
Dim aProperty As New com.sun.star.beans.PropertyValue
|
Тип any
В OpenOffice.org API часто используется тип any, соответствующий типу Variant, широко известному благодаря некоторым средам разработки...
Тип any может содержать один (произвольный) тип UNO. Особенно часто тип any используется в родовых интерфейсах UNO.
Тип any входит в структуру com.sun.star.beans.PropertyValue:
Эта структура имеет два члена: Name и Value, которые в паре описывают свойство по имени и значению. Для работы с такими структурами следует назначать тип any – и быть в состоянии интерпретировать полученный тип any.
В Java тип any соответствует java.lang.Object, однако есть и специальный класс com.sun.star.uno.Any, используемый тогда, когда применение обычного Object было бы неоднозначно. Когда предполагается передача значения типа any, всегда передается java.lang.Object или объект UNO.
Например, если используется метод setPropertyValue() для установки значения неинтерфейсного типа, следует передавать java.lang.Object. Если значение имеет примитивный тип Java, используется соответствующий ему объектный тип:
xCellProps.setPropertyValue("CharWeight", new Double(200.0));
//...
// Или так:
//...
com.sun.star.beans.PropertyValue aProperty = new com.sun.star.beans.PropertyValue();
aProperty.Name = "ReadOnly";
aProperty.Value = Boolean.TRUE; |
При получении значения типа any следует использовать com.sun.star.uno.AnyConverter.
Например, если нужно получить значение свойства, которое имеет примитивный тип Java, следует иметь в виду, что метод getPropertyValue() вернет java.lang.Object, содержащий примитивный тип, "обернутый" в тип any.
com.sun.star.uno.AnyConverter служит преобразователем для таких объектов.
Вот список его функций:
static java.lang.Object toArray(java.lang.Object object)
static boolean toBoolean(java.lang.Object object)
static byte toByte(java.lang.Object object)
static char toChar(java.lang.Object object)
static double toDouble(java.lang.Object object)
static float toFloat(java.lang.Object object)
static int toInt(java.lang.Object object)
static long toLong(java.lang.Object object)
static java.lang.Object toObject(Class clazz, java.lang.Object object)
static java.lang.Object toObject(Type type, java.lang.Object object)
static short toShort(java.lang.Object object)
static java.lang.String toString(java.lang.Object object)
static Type toType(java.lang.Object object)
static int toUnsignedInt(java.lang.Object object)
static long toUnsignedLong(java.lang.Object object)
static short toUnsignedShort(java.lang.Object object) |
При этом использовать его следует явно, например:
import com.sun.star.uno.AnyConverter;
long cellColor = AnyConverter.toLong(xCellProps.getPropertyValue("CharColor")); |
Для интерфейсных типов можно сразу использовать UnoRuntime.queryInterface без предварительного вызова AnyConverter.getObject():
import com.sun.star.uno.AnyConverter;
import com.sun.star.uno.UnoRuntime;
Object ranges = xSpreadsheet.getPropertyValue("NamedRanges");
XNamedRanges ranges1 = (XNamedRanges) UnoRuntime.queryInterface(
XNamedRanges.class, AnyConverter.toObject(XNamedRanges.class, r));
XNamedRanges ranges2 = (XNamedRanges) UnoRuntime.queryInterface(
XNamedRanges.class, r); |
В OpenOffice.org Basic тип any соответствует типу Variant:
'OpenOffice.org Basic
Dim cellColor As Variant
cellColor = oCellProps.CharColor
|
В C++ используем специальный оператор:
//C++ имеет специальные операторы <<= и >>= для типа Any (угловые скобки всегда располагаются слева)
sal_Int32 cellColor;
Any any;
any = rCellProps->getPropertyValue(OUString::createFromAscii( "CharColor" ));
// извлекаем значение из any
any >>= cellColor; |
Последовательность
Последовательность – однородный набор значений одного и того же типа UNO, который может содержать различное число элементов. В других распространенных языках подобные сущности называются массивами (имеются в виду одномерные массивы-векторы). Хотя подобные наборы иногда реализуются как объекты с методами доступа, принятыми в UNO (например, при помощи интерфейса com.sun.star.container.XEnumeration), они также выступают как последовательности, которые могут использоваться в целях повышения удаленной производительности. Последовательности изображаются с угловыми скобками.
//последовательность строк
sequence< string > aStringSequence; |
В Java последовательности обрабатываются как массивы (не следует использовать null для пустых последовательностей, надо создавать массив при помощи слова new и определять ему нулевую длину). Следует также помнить, что при создании массива объектов Java будет создан массив ссылок, а не экземпляров объектов. Поэтому после создания массива надо будет создавать каждый объект в отдельности и присваивать его члену массива (в цикле).
Пустая последовательность структур PropertyValue чаще всего применяется с loadComponentFromURL.
// создаем пустой массив структур PropertyValue для loadComponentFromURL
PropertyValue[] emptyProps = new PropertyValue[0]; |
Последовательность структур PropertyValue нужна для использования загрузки параметров с loadComponentFromURL(). Допустимые значения параметров для loadComponentFromURL() и для интерфейса com.sun.star.frame.XStorage можно найти в сервисе
com.sun.star.document.MediaDescriptor.
//создаем массив с одной структурой PropertyValue для loadComponentFromURL, он содержит ссылку
PropertyValue[] loadProps = new PropertyValue[1];
//создаем экземпляр структуры PropertyValue и инициализируем поля
PropertyValue asTemplate = new PropertyValue();
asTemplate.Name = "AsTemplate";
asTemplate.Value = Boolean.TRUE;
//присваиваем полученную структуру PropertyValue первому элементу массива
loadProps[0] = asTemplate;
//загружаем файл Calc как шаблон
XComponent xSpreadsheetComponent = xComponentLoader.loadComponentFromURL
(
"file:///X:/share/samples/english/spreadsheets/OfficeSharingAssoc.sxc",
"_blank", 0, loadProps
); |
В OpenOffice.org Basic пустой массив создается просто:
Dim loadProps() 'пустой массив
|
Последовательность структур создается с использованием new:
Dim loadProps(0) As New com.sun.star.beans.PropertyValue 'одна структура PropertyValue
|
В C++ есть шаблон класса для последовательностей. Пустая последовательность создается без указания числа элементов:
Sequence< ::com::sun::star::beans::PropertyValue > loadProperties; //пустая последовательность
Если передается число элементов, создается массив элементов нужной длины:
Sequence< ::com::sun::star::beans::PropertyValue > loadProps( 1 );
//структура создается с конструктором по умолчанию
loadProps[0].Name = OUString::createFromAscii( "AsTemplate" );
loadProps[0].Handle <<= true;
Reference< XComponent > rComponent = rComponentLoader->loadComponentFromURL
(
OUString::createFromAscii("private:factory/swriter"),
OUString::createFromAscii("_blank"),
0,
loadProps
); |
Доступ к элементу набора
Наборы объектов должны быть обеспечены методами доступа к элементам. Есть три основных метода доступа: посредством интерфейсов com.sun.star.container.XNameContainer, com.sun.star.container.XIndexContainer и com.sun.star.container.XEnumeration.
Три интерфейса доступа к элементу – пример того, как малоразмерные интерфейсы OpenOffice.org API позволяют создать связный дизайн объекта.
Все три интерфейса наследуют от XElementAccess, то есть включают методы
type getElementType()
boolean hasElements() |
для получения основной информации о наборе элементов. Метод hasElements() определяет, содержит ли набор элементы вообще, и какого типа. В Java и C++ можно получить информацию о типе UNO при помощи com.sun.star.uno.Type.
Интерфейсы com.sun.star.container.XIndexContainer и com.sun.star.container.XNameContainer имеют сходный дизайн.
Интерфейсы XIndexAccess/XNameAccess предназначены для получения элемента по индексу и по имени соответственно, XIndexReplace/XNameReplace позволяют заменять существующие элементы без изменения числа элементов в наборе, и, наконец, XIndexContainer/XNameContainer предоставляют возможность вставлять и удалять элементы, изменяя их число в наборе.
Некоторые именованные или индексированные наборы не полностью поддерживают эту иерархию наследования XIndex(Name)Container – потому что возможности подклассов не всегда применимы для элементов набора.
Например, интерфейс XEnumerationAccess работает по-другому, нежели именованные и индексированные контейнеры-наследники XElementAcces. Интерфейс XEnumerationAccess не позволяет работу с единичными элементами наподобие XIndex(Name)Access, но создает перечисление объектов, имеющее методы для перехода на следующий элемент набора – если указатель находится не на последнем элементе (то есть для перебора элементов набора). Вот схема:
Наборы объектов могут поддерживать доступ к элементам по имени, индексу или доступ по типу перечисления – в различных сочетаниях. В каждом конкретном случае следует обращаться к справке API.
Например, метод getSheets() интерфейса com.sun.star.sheet.XSpreadsheetDocument определен так, чтобы возвращать интерфейс com.sun.star.sheet.XSpreadsheets, унаследованный от XNameContainer. В справке API можно узнать также, что реализующий эти интерфейсы объект также поддерживает сервис com.sun.star.sheet.Spreadsheets, определяющий дополнительные интерфейсы доступа к элементам, помимо XSpreadsheets.
Ниже приведены примеры работы с XNameAccess, XIndexAccess и XEnumerationAccess.
Доступ по имени
Основной интерфейс, предоставляющий доступ к элементу по имени – com.sun.star.container.XNameAccess. Он имеет три метода:
any getByName( [in] string name)
sequence< string > getElementNames()
boolean hasByName( [in] string name) |
В примере FirstLoadComponent метод getSheets() возвращает интерфейс com.sun.star.sheet.XSpreadsheets, унаследованный от XNameAccess. Поэтому возможно использовать метод getByName() для получения объекта листа от контейнера XSpreadsheets.
XSpreadsheets xSpreadsheets = xSpreadsheetDocument.getSheets();
Object sheet = xSpreadsheets.getByName("Новый лист");
XSpreadsheet xSpreadsheet = (XSpreadsheet)UnoRuntime.queryInterface(
XSpreadsheet.class, sheet);
// используется интерфейс XSpreadsheet для получения ячейки A1 в позиции 0,0 и ввода значения 42
XCell xCell = xSpreadsheet.getCellByPosition(0, 0); |
Так как getByName() возвращает тип any, следует использовать AnyConverter.toObject() и(или) UnoRuntime.queryInterface() для возможности обращения к методам объекта листа.
Доступ по индексу
Интерфейс, осуществляющий доступ к элементу набора по индексу – com.sun.star.container.XIndexAccess. Он имеет два метода:
any getByIndex( [in] long index)
long getCount() |
Пример FirstLoadComponent демонстрирует применение этого интерфейса. Из справки API можно узнать, что сервис, возвращаемый методом getSheets() – com.sun.star.sheet.Spreadsheet, – поддерживает не только интерфейс com.sun.star.sheet.XSpreadsheets, но и XIndexAccess.
Поэтому становится возможным обращение к листам не только по имени, но и по индексу:
XIndexAccess xSheetIndexAccess = (XIndexAccess)UnoRuntime.queryInterface(
XIndexAccess.class, xSpreadsheets);
Object sheet = XSheetIndexAccess.getByIndex(0); |
Доступ к перечислению
Интерфейс com.sun.star.container.XEnumerationAccess создает перечисления, позволяющие перебор набора объектов. У него один метод:
com.sun.star.container.XEnumeration createEnumeration()
Интерфейс com.sun.star.container.XEnumerationAccess поддерживает интерфейс com.sun.star.container.XEnumeration. С его помощью можно осуществлять перебор перечисления.
XEnumeration имеет методы:
boolean hasMoreElements()
any nextElement() |
используемые для построения циклов типа:
while (xCells.hasMoreElements())
{
Object cell = xCells.nextElement();
//что-то делаем с объектом cell
} |
Например, так можно определить, какие ячейки таблицы содержат формулы. Результирующий набор объектов cell рассматривается как XEnumerationAccess.
Интерфейс, запрашивающий ячейки с формулами – com.sun.star.sheet.XCellRangesQuery, имеющий, в частности, метод
XSheetCellRanges queryContentCells(short cellFlags)
определяющий тип содержимого ячейки в соответствии с группой констант com.sun.star.sheet.CellFlags. Один из этих флагов – FORMULA.
Метод queryContentCells() возвращает объект, поддерживающий интерфейс com.sun.star.sheet.XSheetCellRanges, имеющий три метода:
XEnumerationAccess getCells()
String getRangeAddressesAsString()
sequence< com.sun.star.table.CellRangeAddress > getRangeAddresses() |
Метод getCells() может использоваться для перечисления всех ячеек с формулами и содержащиеся в них формулы.
XCellRangesQuery xCellQuery =
(XCellRangesQuery)UnoRuntime.queryInterface(
XCellRangesQuery.class, sheet);
XSheetCellRanges xFormulaCells = xCellQuery.queryContentCells(
(short)com.sun.star.sheet.CellFlags.FORMULA);
XEnumerationAccess xFormulas = xFormulaCells.getCells();
XEnumeration xFormulaEnum = xFormulas.createEnumeration();
while (xFormulaEnum.hasMoreElements())
{
Object formulaCell = xFormulaEnum.nextElement();
// do something with formulaCell
xCell = (XCell)UnoRuntime.queryInterface(XCell.class, formulaCell);
XCellAddressable xCellAddress = (XCellAddressable)UnoRuntime.queryInterface(
XCellAddressable.class, xCell);
System.out.println("Ячейке в строке " + xCellAddress.getCellAddress().Column +
", ряду " + xCellAddress.getCellAddress().Row +
" содержит формулу " + xCell.getFormula());
} |
Как определить тип полученного объекта
Общая проблема – определить, какие возможности имеет объект после его получения от метода.
Методы могут быть определены так, чтобы вернуть один тип интерфейса. Но объект, получаемый от метода (как его возвращаемое значение) зачастую поддерживает гораздо больше интерфейсов, нежели возвращает метод (особенно если дизайн этих интерфейсов предшествовал возможностям множественно-унаследованных интерфейсов UNO). Кроме того, интерфейс ничего не сообщает о свойствах объекта.
В OpenOffice.org Basic можно ознакомиться со свойствами объекта, используя следующие свойства Basic:
Sub main
oDocument = ThisComponent
MsgBox(oDocument.Dbg_Methods)
MsgBox(oDocument.Dbg_Properties)
MsgBox(oDocument.Dbg_SupportedInterfaces)
End Sub
|
Пример: работа с текстом, таблицей и фигурой
Далее рассмотрим пример общих приемов работы с OpenOffice.org API. Три основные области приложения OpenOffice.org – текст, таблицы и рисунки.
Общие механизмы работы
Начнем с общих интерфейсов и свойств, позволяющими манипулировать существующими текстами, таблицами и рисунками. Далее будут рассмотрены другие приемы, предназначенные для создания таких документов.
Для работы с существующими текстами, таблицами и рисунками применяются следующие основные интерфейсы.
Для текстовых документов интерфейс com.sun.star.text.XText содержит методы, позволяющие изменять "основной" текст документа и другое текстовое содержимое (таблицы, текстовые поля, графические объекты и т.п., но подобное допустимо не всегда).
Интерфейс com.sun.star.text.XText может устанавливать и возвращать текст как единичную строку и определять начало и конец текста. Также этот интерфейс может вставлять строку в произвольную позицию в тексте и создавать текстовые курсоры для выбора и форматирования текста. Кроме того, этот интерфейс может обрабатывать текстовый контент методами insertTextContent и removeTextContent, хотя это и не всегда возможно.
Форматирование текста обеспечивается свойствами, имеющимися в сервисах com.sun.star.style.ParagraphProperties и com.sun.star.style.CharacterProperties.
В последующем примере метод manipulateText() добавляет текст, используя текстовый курсор для выделения и форматирования некоторых слов и применяя CharacterProperties. Метод manipulateText() содержит лишь основные методы XText, применимые для работы с любыми текстовыми объектами. Например, не применяется метод insertTextContent() – потому, что нет текстового контента, исключая обычный текст, который можно вставить во все текстовые объекты.
Изучите функцию manipulateText() в коде примера HelloTextTableShape.
В таблицах и ячейках таблиц интерфейс com.sun.star.table.XCellRange позволяет получать отдельные ячейки и поддиапазоны ячеек. С содержимым ячейки можно работать при помощи интерфейса com.sun.star.table.XCell.
Форматирование таблиц отличаются для текстовых таблиц Writer и таблиц Calc. Текстовые таблицы применяют свойства, описанные в com.sun.star.text.TextTable, а таблицы Calc – com.sun.star.table.CellProperties. Также есть объекты-табличные курсоры, позволяющие выбирать и форматировать регионы ячеек и содержащийся в них текст. Но com.sun.star.text.TextTableCursor работает по-другому, чем com.sun.star.sheet.SheetCellCursor.
Изучите функцию manipulateTable() в тексте примера HelloTextTableShape.
Для фигур Draw используется интерфейс com.sun.star.drawing.XShape, позволяющий определить позицию и размер фигуры.
Все остальное определяется при помощи основанного на свойствах форматирования. Есть много свойств для форматирования фигур. OpenOffice.org имеет одиннадцать фигур, на которых основаны средства для рисования. Шесть из них имеют собственные свойства, отражающие их характеристики:
Пять фигур не имеют индивидуальных свойств, а используют свойства, определенные в сервисе com.sun.star.drawing.PolyPolygonBezierDescriptor:
Все эти одиннадцать фигур используют свойства от следующих сервисов:
Обратитесь к функции manipulateShape() в коде примера HelloTextTableShape.
Создание текста, электронной таблицы и рисование фигур
Три метода manipulateXXX в примере HelloTextTableShape получают текст, таблицу и фигуру как аргументы и изменяют их.
Далее следует рассмотреть, как создавать подобные объекты в документах различного типа.
Надо помнить, что все документы имеют собственные "фабрики" для создания вставляемых объектов. Кроме того, методики могут отличаться для разных типов документов.
Сначала следует создать новый документ, что делается довольно просто – см. функцию newDocComponent() в тексте примера.
Текст, таблицы и фигуры в Writer
Метод useWriter создает документ Writer, изменяет его текст, затем использует менеджер сервисов документа для создания текстовой таблицы и фигуры, вставки их в документ и изменения в дальнейшем. Следует изучить функцию useWriter() в примере HelloTextTableShape.
Текст, таблицы и фигуры в Calc
Метод useCalc нашего примера создает документ Calc, применяет его "фабрику документов" для создания фигуры и изменения текста в ячейках, таблицы и фигуры. Изучите функцию useCalc() подробнее.
Рисование и текст в Draw
Наконец, метод useDraw создает документ Draw, добавляя к нему фигуру и изменяя ее. Подробнее – смотрите текст функции useDraw().
Пример приложеня
FirstUnoContact.java
import com.sun.star.comp.helper.Bootstrap;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
public class FirstUnoContact {
public static void main (String[] args){
//всего одна функция
//по завершении которой прекращаем работу
try{
//создаем компонентный контекст
XComponentContext xContext = Bootstrap.bootstrap();
//выводим сообщение
System.out.println("Соединяемся с работающим экземпляром OOffice... ");
//создаем основную фабрику объектов
XMultiComponentFactory xMCF = xContext.getServiceManager();
//проверяем, получилось ли создать?
String avaiable = (xMCF != null ? "доступен":"не доступен");
//и сообщаем о результате
System.out.println("удаленный ServiceManager " + avaiable);
}
catch(Exception e){
//при исключении – выводим дамп стека
e.printStackTrace();
}
finally{
//выходим без ошибки
System.exit(0);
}
}
} |
Источник
Сайт:
OpenOffice.org Developer Guide – Ch.2 First Steps
Перевод
Автор перевода:
Буханцов Дмитрий Владимирович
Обсудить
на форуме:
community.i-rs.ru
Содержание статьи
Присоединенные файлы