В прошлый раз я обещал написать про то, как деплоить OSGi-приложение в сервлет-контейнерах, отличных от Jetty. Для решения данной задачи используется Equinox ServletBridge, однако, прежде чем разбираться с данным механизмом, необходимо вникнуть в основы построения и деплоймента Eclipse RCP-приложений. О деплойменте поговорим чуть позже, а сегодня разберемся с тем, что такое "приложение" в терминах Eclipse RCP.
Приложением называется класс, реализующий интерфейс IApplication. В каком-то смысле приложение является точкой входа в Eclipse RCP и является аналогом метода main Java или C/C++ программы. В поставку Eclipse Plugins Development Environment включено несколько примеров приложений. Вот код класса, реализующего интерфейс IApplication из примера Hello RCP:
package name.samolisov.plugins.app;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* This class controls all aspects of the application's execution
*/
public class Application implements IApplication {
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* This class controls all aspects of the application's execution
*/
public class Application implements IApplication {
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/* (non-Javadoc)
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
В методе start происходит инициализация приложения. В данном случае здесь создается workbench и регистрируется менеджер связки "воркбенч - окно", в котором, в свою очередь, регистрируется непосредственно главное окно приложения. Метод start может возвращать следующие значения типа Integer, которые являются некоторым аналогом кода завершения приложения:
- IApplication.EXIT_OK - приложение запущено корректно.
- IApplication.EXIT_RESTART - приложение требует перезапуска платформы
- IApplication.EXIT_RELAUNCH - приложение требует останова и нового запуска платформы. Обычно данный код возвращают, если требуется запуск приложения с какими-то другими аргументами командной строки.
В методе stop, соответственно, происходит освобождение ресурсов, общих для всего приложения. В данном примере - происходит закрытие воркбенча.
В случае, если разрабатывается веб-приложение, запускаемое в сервлет-контейнере Jetty, код класса может быть таким:
package name.samolisov.plugins.app;
import java.util.Dictionary;
import java.util.Hashtable;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.http.jetty.JettyConfigurator;
public class WebApplication implements IApplication
{
private static final String HTTP_PORT_KEY = "http.port";
private static final int HTTP_PORT = 8080;
private static final String SERVER_NAME = "demojetty";
@Override
public Object start(IApplicationContext context) throws Exception
{
Dictionary<String, Object> properties = new Hashtable<String, Object>();
properties.put(HTTP_PORT_KEY, HTTP_PORT);
JettyConfigurator.startServer(SERVER_NAME, properties);
System.out.println("Server " + SERVER_NAME + " has been started");
return EXIT_OK;
}
@Override
public void stop()
{
try
{
JettyConfigurator.stopServer(SERVER_NAME);
System.out.println("Server " + SERVER_NAME + " has been stoped");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
import java.util.Dictionary;
import java.util.Hashtable;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.equinox.http.jetty.JettyConfigurator;
public class WebApplication implements IApplication
{
private static final String HTTP_PORT_KEY = "http.port";
private static final int HTTP_PORT = 8080;
private static final String SERVER_NAME = "demojetty";
@Override
public Object start(IApplicationContext context) throws Exception
{
Dictionary<String, Object> properties = new Hashtable<String, Object>();
properties.put(HTTP_PORT_KEY, HTTP_PORT);
JettyConfigurator.startServer(SERVER_NAME, properties);
System.out.println("Server " + SERVER_NAME + " has been started");
return EXIT_OK;
}
@Override
public void stop()
{
try
{
JettyConfigurator.stopServer(SERVER_NAME);
System.out.println("Server " + SERVER_NAME + " has been stoped");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Класс-приложение необходимо зарегистрировать. Для этого служит точка расширения org.eclipse.core.runtime.applications. Воспользоваться ею можно следующим образом:
<extension
id="name.samolisov.plugins.app.application"
point="org.eclipse.core.runtime.applications">
<application>
<run
class="name.samolisov.plugins.app.Application">
</run>
</application>
</extension>
id="name.samolisov.plugins.app.application"
point="org.eclipse.core.runtime.applications">
<application>
<run
class="name.samolisov.plugins.app.Application">
</run>
</application>
</extension>
После регистрации приложение становится доступно для запуска. Его можно выбрать в качестве значения параметра Run an application конфигурации запуска (соответственно, при нажатии кнопки Run, будет запущен не Eclipse, а наше приложение):
Если бандл с приложением поместить в каталог plugins инсталяции Eclipse, то запустить приложение можно будет из командной строки, указав его идентификатор в качестве значения параметра -application:
eclipse.exe -application name.samolisov.plugins.app.application
Теперь рассмотрим развертывание приложения отдельно от инсталяции Eclipse. Для этого необходимо создать следующую структуру каталогов (подробнее о структуре каталогов и запуске Equinox) можно прочесть здесь):
\demo
---\configuration
------config.ini
---eclipse.exe
---\plugins
------\org.eclipse.equinox.launcher.win32.win32.x86_1.0.100
---------eclipse.dll
В каталог plugins необходимо скопировать все плагины, которые требуются для бандла с приложением. В случае приложения Hello RCP, входящего в набор примеров Eclipse PDE, необходимы следующие бандлы:
com.ibm.icu
name.samolisov.plugins.app
org.eclipse.core.commands
org.eclipse.core.contenttype
org.eclipse.core.databinding.observable
org.eclipse.core.databinding.property
org.eclipse.core.databinding
org.eclipse.core.expressions
org.eclipse.core.jobs
org.eclipse.core.runtime.compatibility.auth
org.eclipse.core.runtime.compatibility.registry
org.eclipse.core.runtime
org.eclipse.equinox.app
org.eclipse.equinox.common
org.eclipse.equinox.launcher.win32.win32.x86
org.eclipse.equinox.launcher
org.eclipse.equinox.preferences
org.eclipse.equinox.registry
org.eclipse.help
org.eclipse.jface.databinding
org.eclipse.jface
org.eclipse.osgi.services
org.eclipse.osgi
org.eclipse.swt.win32.win32.x86
org.eclipse.swt
org.eclipse.ui.workbench
org.eclipse.ui
Файл configuration/config.ini должен иметь следующее содержание:
#Product Runtime Configuration File
osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.jobs@start,org.eclipse.equinox.registry@start,org.eclipse.equinox.preferences@start,org.eclipse.core.contenttype@start,org.eclipse.equinox.app@start,org.eclipse.core.runtime@start,org.eclipse.core.commands@start,org.eclipse.ui.workbench@start,org.eclipse.help@start,org.eclipse.swt@start,org.eclipse.jface@start,org.eclipse.ui@start,org.eclipse.core.expressions@start,com.ibm.icu@start,org.eclipse.jface.databinding@start,org.eclipse.core.databinding.observable@start,org.eclipse.core.databinding.property@start,org.eclipse.core.databinding@start,org.eclipse.swt.win32.win32.x86@start,name.samolisov.plugins.app@start
osgi.bundles.defaultStartLevel=4
eclipse.application=name.samolisov.plugins.app.application
osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.jobs@start,org.eclipse.equinox.registry@start,org.eclipse.equinox.preferences@start,org.eclipse.core.contenttype@start,org.eclipse.equinox.app@start,org.eclipse.core.runtime@start,org.eclipse.core.commands@start,org.eclipse.ui.workbench@start,org.eclipse.help@start,org.eclipse.swt@start,org.eclipse.jface@start,org.eclipse.ui@start,org.eclipse.core.expressions@start,com.ibm.icu@start,org.eclipse.jface.databinding@start,org.eclipse.core.databinding.observable@start,org.eclipse.core.databinding.property@start,org.eclipse.core.databinding@start,org.eclipse.swt.win32.win32.x86@start,name.samolisov.plugins.app@start
osgi.bundles.defaultStartLevel=4
eclipse.application=name.samolisov.plugins.app.application
В данном файле для нас важна строчка eclipse.application=name.samolisov.plugins.app.application, задающая приложение по-умолчанию. Теперь для запуска не нужно указывать параметр командной строки -application, а можно просто запускать файл eclipse.exe.
Понятно, что неудобно каждый раз руками отслеживать зависимости бандлов и копировать плагины вручную. Так же неудобно вручную прописывать значения в файле config.ini. Хочется, чтобы все это делалось автоматически. К тому же, иногда хочется добавить к приложению какой-то брендинг - иконки запуска, ярлычок, указать лицензию и т.д. Для этого в Eclipse RCP существует такое понятие, как "Продукт". Однако, это уже тема другого разговора.
Понравилось сообщение - подпишитесь на блог или читайте меня в twitter
"Понятно, что неудобно каждый раз руками отслеживать зависимости бандлов и копировать плагины вручную. Так же неудобно вручную прописывать значения в файле config.ini. Хочется, чтобы все это делалось автоматически. К тому же, иногда хочется добавить к приложению какой-то брендинг - иконки запуска, ярлычок, указать лицензию и т.д. Для этого в Eclipse RPC существует такое понятие, как "Проект"."
ОтветитьУдалить)) Перед сдачей курсового за час до сдачи выяснили, что плугинов насоздавали, из эклипса свою рсп запустить можем, а как сделать без эклипса? Пришлось за полчаса разобраться с этим проектомом :)
Полчаса - тоже время. Напишу заметку, вдруг, кому-то пригодится.
ОтветитьУдалитьАга, было бы полезно. Потому как тогда на адреналине сделал, а теперь заставь повторить - сомневаюсь, что смогу с ходу.
ОтветитьУдалитьЗдравствуйте.
ОтветитьУдалитьгде вызывается метод stop()?
у меня вообще такого метода нет, только run()
вся глупость в том, что когда закрываю главное окно своего rcp приложения, другие окна не закрываются
Метод stop() будет автоматически вызван платформой при завершении приложения (например, при выгрузке соответствующего бандла).
ОтветитьУдалить