DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. OSGi Service Hook to Log All Service Invocations Using Dynamic Proxy

OSGi Service Hook to Log All Service Invocations Using Dynamic Proxy

Slim Ouertani user avatar by
Slim Ouertani
·
Dec. 28, 09 · Interview
Like (0)
Save
Tweet
Share
16.35K Views

Join the DZone community and get the full member experience.

Join For Free

In this post, I will present an elegant solution to log all services invocations in an OSGi environment. After developing and using some bundles we need to know for different reasons which services are used by such a bundle, when invocation are occurred and what parameters are passed to services. So, should I log all service invocations? It's impossible. First, you need to change all the source code of your bundles. Second, other bundles are proprietary and you haven't their source code .

But thanks to service hooks, introduced in 4.2 Osgi release, we can do it in easy way.

Service Hooks

Service hooks are the second face of OSGi :) . As we know how to get and listen to services,  hooks provide a way to know and manage whose bundles are waiting or tacking services. The goal of this solution is to present  FindHook and  EventHook services use case to log all service invocations.

Solution Description

logger proxy flow

When service is registered, we create another copy (delegation) using dynamic proxy and register it using source bundle class loader and add the proxied property. When some bundle needs to use this service we hide the first one and effectively that bundle will get the proxied service.

Solution

- The EventHook interface has only one method to implement :
 @Override    public void event(ServiceEvent event, Collection contexts) {
final ServiceReference serviceReference = event.getServiceReference();
System.out.println("" + serviceReference.getBundle().getSymbolicName());

if (serviceReference.getProperty(PROXY) == null && serviceReference.getBundle().getBundleContext() != bc) {
Bundle bundle = serviceReference.getBundle();

switch (event.getType()) {
case REGISTERED: {

String[] propertyKeys = serviceReference.getPropertyKeys();
Properties properties = buildProps(propertyKeys, event);
String[] interfaces = (String[]) serviceReference.getProperty(
"objectClass");

Class[] toClass = toClass(interfaces, bundle);
proxyService(bundle,
toClass,
properties,
this.getClass().getClassLoader(), new LoggerProxy(
bc, serviceReference));



break;
}
case UNREGISTERING: {
//TODO
break;
}
case MODIFIED:
case MODIFIED_ENDMATCH: {
//TODO
break;
}
}
}
}
Before event delivery this method will be called. We check if the service is not already proxied. If it is a new service, we create another one using its declared interfaces, all its properties and another property "proxied".

 

- The FindHook interface has only one method to implement
 @Override    public void find(BundleContext bc, String name, String filter,
boolean allServices, Collection references) {
try {
if (this.bc.equals(bc) || bc.getBundle().getBundleId() == 0) {
return;
}

System.out.println(
" bundle : [" + bc.getBundle().getSymbolicName() + "] try to get reference of " + name);
Iterator iterator = references.iterator();

while (iterator.hasNext()) {
ServiceReference sr = (ServiceReference) iterator.next();

System.out.println(
"from bundle" + sr.getBundle().getSymbolicName());

if (sr.getProperty("proxied") == null) {
iterator.remove();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
This method is called during the service find operation, in this method callback we hide all services that aren't proxied.

The LoggerProxy is a sample proxy to log all invocation and forward call to effective refreence.

public class LoggerProxy implements InvocationHandler, Serializable {
private ServiceReference serviceReference;
private BundleContext bundleContext;

public LoggerProxy(BundleContext bundleContext,
ServiceReference serviceReference) {
this.serviceReference = serviceReference;
this.bundleContext = bundleContext;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-->Methode : [" + method.getName() + "] ");
System.out.println("-->Parameters : ");
for (Object object : args) {
System.out.print("->"+object + " : ");
}
System.out.println("");
Object invoke = method.invoke(bundleContext.getService(serviceReference),
args);

System.out.println("-->Return : " + invoke);
return invoke;
}
}

At the end we register our services using an Activator :

public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
LoggerHooks loggerHooks = new LoggerHooks(context);
context.registerService(new String[]{FindHook.class.getName(), EventHook.class.getName()},
loggerHooks, null);

}

@Override
public void stop(BundleContext context) throws Exception {
}
}

Console Output


When bundle 34 starts, it tries to get the TService service from bundle 33

osgi> start 34
bundle : [demo.client_0.1] try to get reference of com.jtunisie.akel.demo.api.TService
from bundledemo.register_0.1
from bundledemo.register_0.1
-->Methode : [echo]
-->Parameters :
->Service Found :
-->Return : Yes !Service Found
Yes !Service Found

Bundle 33 register two services one is proxied.

osgi> b 33demo.register_0.1_0.0.0 [33]
Id=33, Status=ACTIVE Data Root=/home/sst/dev/4.2hooks/configuration/org.eclipse.osgi/bundles/33/data
Registered Services
{com.jtunisie.akel.demo.api.TService}={service.id=44}
{com.jtunisie.akel.demo.api.TService}={service.id=45, proxied=true}
No services in use.
Exported packages
com.jtunisie.akel.demo.service.impl; version="0.0.0"[exported]
Imported packages
com.jtunisie.akel.demo.api; version="0.0.0"
org.osgi.framework; version="1.5.0"
scala; version="0.0.0"
No fragment bundles
Named class space
demo.register_0.1; bundle-version="0.0.0"[provided]
No required bundles

Conclusio

Dynamic proxy and service hooks provide a powerful tool to mange complicated OSGi use cases. This post shows one use case using find and event hooks to log all service invocations. In the second post I will try to present Listener Hook and a way to distribute Osgi service transparently.

source code is under svn : svn checkout http://osgiservicelogger.googlecode.com/svn/trunk/ osgiservicelogger-read-only
Hook

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Spring Boot, Quarkus, or Micronaut?
  • Real-Time Analytics for IoT
  • 5 Software Developer Competencies: How To Recognize a Good Programmer
  • Key Elements of Site Reliability Engineering (SRE)

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: