Java OSGi Tutorial

category 백엔드/개발 2022. 5. 3. 10:43
728x90
반응형

Github 소스

 

Tutorial (튜토리얼)

1. OSGi "MathConsumer" 생성

1-1. MathConsumer 프로젝트 생성

Activator Code

package org.tutorial.helloosgi.mathconsumer;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;
		System.out.println("MathConsumer Starting...");
		System.out.println("MathConsumer Started");
	}

	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
		System.out.println("MathConsumer Stopped");
	}
}

2-2. MathConsumer 번들 구성

OSGi 번들을 구성하기 위하여 Dependencies에 다음과 같은 Plug-in을 추가해주자.

  • org.eclipse.osgi
  • org.eclipse.equinox.console
  • org.apache.felix.gogo.command
  • org.apache.felix.gogo.runtime
  • org.apache.felix.gogo.shell

2-3. MathConsumer 실행 설정

프로젝트에서 마우스 오른쪽 버튼을 눌러 Run As > Run Configurations를 클릭해준다.

마우스 오른쪽 버튼을 눌러 New Configuration을 클릭한다.

Workspace를 제외한 나머지 Target Platform을 해제시키고 Apply를 클릭한다.

Add Required Bundles를 클릭 → Only show selected Apply Run 순서대로 실행한다.

2-3. MathConsumer 시작

Run을 클릭하면 OSGi MathConsumer가 실행될 것이다. Bundle 목록을 볼 수 있으며 start, stop을 실행시킬 수 있다.

3. OSGi "MathService" 생성

3-1. MathService 프로젝트 생성

3-2. MathService 작성 Service Register 등록

다음과 같은 Package에 Class를 구성한다.

MathService.java

package org.tutorial.helloosgi.mathservice;

public interface MathService {
	public int sum(int a, int b);
}

MathServiceImpl.java

package org.tutorial.helloosgi.mathservice.impl;

import org.tutorial.helloosgi.mathservice.MathService;

public class MathServiceImpl implements MathService {

	@Override
	public int sum(int a, int b) {
		return a + b;
	}
}

MathUtils.java

package org.tutorial.helloosgi.utils;

public class MathUtils {
	public static int minus(int a, int b) {
		return a - b;
	}
}

Activator.java

package org.tutorial.helloosgi;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.tutorial.helloosgi.mathservice.MathService;
import org.tutorial.helloosgi.mathservice.impl.MathServiceImpl;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;
		System.out.println("Registry Service MathService...");
		this.registryMathService();
		System.out.println("OSGi MathService Started");
	}

	private void registryMathService() {
		MathService service = new MathServiceImpl();
		context.registerService(MathService.class, service, null);
	}

	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
		System.out.println("OSGi MathService Stopped!");
	}

}

3-3. OSGi MathService 번들 구성

다음과 같은 두 패키지를 Exported Packaged로 구성하여 외부에서 호출 가능하도록 한다.

  • org.tutorial.helloosgi.utils and 
  • org.tutorial.helloosgi.mathservice

4. MathConsumer에서 MathService 사용하도록 설정 및 실행

Activator.java파일을 아래와 같이 재편집하도록 한다.

 

Activator.java

package org.tutorial.helloosgi.mathconsumer;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.tutorial.helloosgi.mathservice.MathService;
import org.tutorial.helloosgi.utils.MathUtils;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;
		System.out.println("MathConsumer Starting...");

		System.out.println("5-3 = " + MathUtils.minus(5, 3));
		ServiceReference<?> serviceReference = context.getServiceReference(MathService.class);
		MathService service = (MathService) context.getService(serviceReference);

		System.out.println("5+3 = " + service.sum(5, 3));
		System.out.println("MathConsumer Started");
	}

	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
		System.out.println("MathConsumer Stopped");
	}
}

 

 

Troubleshooting

원인

  • context가 service를 찾지 못해서 발생하는 문제이다. 

해결방안

  1. MANIFEST.MF 파일에서 Runtime에서 Exported Packages 지정을 하였는지 살펴본다.
  2. bundle 시작 순서를 명시적으로 지정하여 해당 service가 먼저 로드되도록 한다.
MathConsumer Starting...
5-3 = 2
Registry Service MathService...
!SESSION OSGi MathService Started
2022-05-03 09:57:35.730 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.8.0_271
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=ko_KR
Command-line arguments:  -dev file:D:/workspace/.metadata/.plugins/org.eclipse.pde.core/Run OSGI MathConsumer/dev.properties -os win32 -ws win32 -arch x86_64 -consoleLog -console

!ENTRY MathConsumer 4 0 2022-05-03 09:57:38.021
!MESSAGE FrameworkEvent ERROR
!STACK 0
org.osgi.framework.BundleException: Exception in org.tutorial.helloosgi.mathconsumer.Activator.start() of bundle MathConsumer.
	at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:834)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:762)
	at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1032)
	at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:371)
	at org.eclipse.osgi.container.Module.doStart(Module.java:605)
	at org.eclipse.osgi.container.Module.start(Module.java:468)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel$2.run(ModuleContainer.java:1847)
	at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor$1$1.execute(EquinoxContainerAdaptor.java:136)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1840)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1783)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1745)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1667)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:234)
	at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:345)
Caused by: java.lang.NullPointerException: A null service reference is not allowed.
	at org.eclipse.osgi.internal.framework.BundleContextImpl.getService(BundleContextImpl.java:653)
	at org.tutorial.helloosgi.mathconsumer.Activator.start(Activator.java:23)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:813)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:1)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:805)
	... 14 more
Root exception:
java.lang.NullPointerException: A null service reference is not allowed.
	at org.eclipse.osgi.internal.framework.BundleContextImpl.getService(BundleContextImpl.java:653)
	at org.tutorial.helloosgi.mathconsumer.Activator.start(Activator.java:23)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:813)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:1)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:805)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:762)
	at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1032)
	at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:371)
	at org.eclipse.osgi.container.Module.doStart(Module.java:605)
	at org.eclipse.osgi.container.Module.start(Module.java:468)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel$2.run(ModuleContainer.java:1847)
	at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor$1$1.execute(EquinoxContainerAdaptor.java:136)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1840)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1783)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1745)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1667)
	at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.dispatchEvent(ModuleContainer.java:1)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:234)
	at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:345)

!ENTRY org.eclipse.osgi 4 0 2022-05-03 09:57:38.065
!MESSAGE Bundle MathConsumer_1.0.0.qualifier [1] is not active.
osgi>

 

참고

https://o7planning.org/10135/java-osgi-tutorial-for-beginners

728x90
반응형