Ouertani Slim was born in Tunisia in 1981. Now he is a software engineer since 2004 and he is Java 6 and Spring certified with 100% and 94% respectively. He is very interested in Java technology, Scala and open source projects. He believes that programming is one of the hardest jobs and most beautiful in the world. Slim has posted 32 posts at DZone. You can read more from them at their website. View Full User Profile

Service Factory and OSGI Logging Proposal

10.08.2008
| 9913 views |
  • submit to reddit

I've been doing some thinking lately about how can we log different bundles  or the same bundle with different versions with different log level.   Logging is an important part of any application thus Osgi gives developers logService to use when possible, but standard logging api (slf4j, log4j) are simple to use.

Why I'm asking this question :
 1 -Working with osgi is a bit different regarding simple java programming: The same class can exist on many bundle with different version (different loader).
 2- Making an upgrade on some bundles by changing the bundle versions :  we should leave the two running  versions  if some other bundles are not updated to use the new milestone version.

I try here to present ServiceFactory utilities and I will present some brainstorming about possible logging enhancement :

ServiceFactory :

We create here three bundles :

1- logger  : contains the api and impl
2- client 1 : using logger service with version 1, as stable implementation the log level is ERROR
3- client 2 : using logger service with version 2.0.0.m1 as unstable implementation the log level is Debug to catch all messages.

Here is the draft implementation of logger class :

package com.jtunisie.osgi.logger.impl;

import com.jtunisie.osgi.logger.Level;
import java.util.Dictionary;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.Version;

public class Logger implements com.jtunisie.osgi.logger.Logger, ServiceFactory {

@Override
public void log(Class clazz, Level level, String msg, Object... params) {
}

@Override
public Object getService(Bundle bundle, ServiceRegistration arg1) {

Dictionary dictionary = bundle.getHeaders();
Version version = Version.parseVersion((String)dictionary.get(org.osgi.framework.Constants.BUNDLE_VERSION));
String name = (String) dictionary.get(org.osgi.framework.Constants.BUNDLE_NAME);

com.jtunisie.osgi.logger.Logger logger = getLogger(name, version);
return logger;

}

private com.jtunisie.osgi.logger.Logger getLogger(String name, Version version) {
if (version.toString().contains("m")) {
return new ErrorLogger();
} else {
return new DebugLogger();

}
}

@Override
public void ungetService(Bundle arg0, ServiceRegistration arg1, Object arg2) {
}
}
package com.jtunisie.osgi.logger.impl;

import com.jtunisie.osgi.logger.Level;

class ErrorLogger implements com.jtunisie.osgi.logger.Logger {

@Override
public void log(Class clazz, Level level, String msg, Object... params) {
if (level.compareTo(Level.ERROR) == 0) {
msg = LoggerUtils.processMsg(params, msg);
System.out.println("----" +clazz+ " :>"+LoggerUtils.getMessage()+"//"+msg);
}

}
}
package com.jtunisie.osgi.logger.impl;

import com.jtunisie.osgi.logger.Level;

class DebugLogger implements com.jtunisie.osgi.logger.Logger{

@Override
public void log(Class clazz, Level level, String msg, Object... params) {
msg = LoggerUtils.processMsg(params, msg);
System.out.println("----" + clazz + " :>"+ LoggerUtils.getMessage()+"//"+msg);
}

}

client 1 and 2 are to simple activator class as

//client 1

package com.jtunisie.osgi.logger.client;

import com.jtunisie.osgi.logger.*;
import static com.jtunisie.osgi.logger.Level.*;

public class Activator {


private Logger logger;

public Activator(Logger logger) {
this.logger = logger;

}
public void init(){
logger.log(Activator.class ,DEBUG, "DEBUG : 1>>>>>My Id is ## version is ## ", 1,1);
logger.log(Activator.class ,ERROR, "ERROR : 1>>>>>My Id is ## version is ## ", 1,1);
}

}
package com.jtunisie.osgi.logger.client;

import com.jtunisie.osgi.logger.*;
import static com.jtunisie.osgi.logger.Level.*;

public class Activator {
private Logger logger;

public Activator(Logger logger) {
this.logger = logger;

}
public void init(){
logger.log(Activator.class ,DEBUG, "DEBUG : 2>>>>>My Id is ## version is ## ", 2,2);
logger.log(Activator.class ,ERROR, "ERROR : 2>>>>>My Id is ## version is ## ", 2,2);
}
}

if we run these examples the out put will be like :

----class com.jtunisie.osgi.logger.client.Activator :>Wed Oct 08 03:25:18 CEST 2008//ERROR : 2>>>>>My Id is 2 version is 2
----class com.jtunisie.osgi.logger.client.Activator :>Wed Oct 08 03:25:18 CEST 2008//DEBUG : 1>>>>>My Id is 1 version is 1
----class com.jtunisie.osgi.logger.client.Activator :>Wed Oct 08 03:25:18 CEST 2008//ERROR : 1>>>>>My Id is 1 version is 1

==> ServiceFactory gives new implementation per bundle client depends on it's version.

Logging proposal :

Many considerations should be taken when osgi is your framework :

 -Class implementation can be found in different bundles version with same package version.
 -Class implementation can be found in different bundles version with different package version.

log4j.dtd does not have the notion of bundle and version and my proposition is :

 

<!ELEMENT log4j:configuration (renderer*, appender*,(category|logger)*,root?,
categoryFactory?)>

Will be

<!ELEMENT log4j:configuration (renderer*, appender*,(bundle|category|logger)*,root?,
categoryFactory?)>

and

we add version to category and logger element


so our log4j.xml file could be :

<category name="com.jtunisie.osgi.logger.client">
<priority value="ERROR" version="[0.0.0,2.0.0("/>
<priority value="DEBUG" version="2.0.0"/>
</category>

or in our case

<bundle name="com.jtunisie.osgi.client">
<priority value="ERROR" version="[0.0.0,1.0.0("/>
<priority value="DEBUG" version="2.0.0"/>
</bundle>
Published at DZone with permission of its author, Slim Ouertani.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Bernd Eckenfels replied on Thu, 2008/10/09 - 8:27pm

I would att the version to "category" and not priority.

Hanen Ben Rhouma replied on Fri, 2008/10/10 - 5:04pm

Interesting post Slim but needs further patience by your side to clarify many details that may seem parachuted for an OSGi newbie.Taking into consideration your project arborescence, your building and deployment steps are mandatory to keep your reader on the right direction, otherwise more than what OSGi word still hold with strangeness for some, your jumping "to the target" won't make things easier for them neither. 

PS: maybe you can host your example sources on any SVN or CVS server and share it with us for pertinent feedbacks

Slim Ouertani replied on Sun, 2008/10/12 - 8:48am in response to: Hanen Ben Rhouma

thanks,

your are right. I haven't a lot of time to do it clear, it was to late to more explain my purpose. thing are more precise in my blog http://www.jroller.com/ouertani/

and for svn source they are available under this URL :

svn checkout http://logosgi.googlecode.com/svn/trunk/ logosgi-read-only

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.