Wednesday, September 24, 2008

Logging in OSGI Enterprise Applications, Part 1



Logging is an important part of ERP Applications and should be easy using a modern logging framework ;-)

My actual work-in-progress (german ERP solution) contains: Equinox as OSGI Framework, Eclipse Riena for Remote Services + UI, EasyBeans as EJB3 Container + JPA (Hibernate) etc.

This means I have to integrate different logging - frameworks:

  • org.osgi.service.log
  • org.eclipse.equinox.log (Extended Log Services from 1.1.0.HEAD)
  • org.apache.commons.logging
  • org.apache.log4j
  • org.slf4j
  • java.util.logging (JSR47)

If you already followed some of my blogs, then you probably know that its not easy to design a clean OSGI architecture for a complex business application.

Actually I was confronted with the newest snapshot of EasyBeans containing a new Hibernate release (3.4) now using SLF4 as logging framework. This causes me to rethink my logging architecture.

The logging solution should make my OSGI client / server - application independent from logging frameworks. I'll explain all in detail later.  At first I'll give you an overview to see the differences between "classic" Java logging frameworks and OSGI Logging Services.

"Classic" Java Logging Frameworks


Usually logging works this way:

Logger definition:

Commons-Logging:
private static Log logger = LogFactory.getLog(MyClass.class);
Log4J:
private static Logger logger = Logger.getLogger(MyClass.class.getName());
SLF4J:
private static Logger logger = LoggerFactory.getLogger(MyClass.class);
JDK:
private static Logger logger = Logger.getLogger(MyClass.class.getName());

Logging a message:

logger.info(„my message“)

Because concatenating Strings is slowly we also find: 

if (logger.isDebugEnabled())
   logger.debug("message part 1" + aVar
   + "message part 2");

Remark: If you're using SLF4J (FAQ) in many cases you can simple use a parameterized message string:

logger.debug("message part 1 {} message part 2", aVar);


Configuring logging - frameworks:

Configuration can be made using Java code - but mostly you'll find a configuration file - wether in properties or XML format. 


Whats different if you're using these logging frameworks under OSGI ?

  • you need a bundle for each JAR. You can find bundles for Commons-Logging, LOG4J and SLF4J partly in Eclipse or get them from a bundle repository
  • logging itself is the same as in normal Java applications
  • you have to place the configuration file into a Fragment-Bundle


OSGI Logging Services

Under OSGI you can use Logging Services:

  • Standard OSGI : org.osgi.log (OSGI Logging, implemented by org.equinox.log)
  • Extended: org.equinox.log (1.1.0.HEAD Version from CVS or Riena download), extended Logging)

OSGI Logging uses Services and Listeners. Equinox implements OSGI Log Services as ManagementServices. 

  • LogService or ExtendedLogService - writes all log messages
  • LogReaderService or ExtendedLogReaderService - where you can read log messages from
  • LogListener - gets the messages from ReaderService and you can handle them

OSGI LogService can be compared with the Logger from "classic" Java logging. Its a good idea to place LogService Logger objects into the Activator of a bundle.

LogService logger = ...

Logging a message is nearly the same as logging in non - OSGI environments - of course we have to test if the service is available:

if (logger != null) {
     logger.log(LogService.LOG_INFO, „my message“);
}

The LogEvent can then be read using the LogReaderService. You can "track" this ReaderService  and add your own LogListener. This LogListener gets all messages and you can persist the messages or print to console or use one of the "classic" logging frameworks.

Equinox allows you to configure how many messages should be cached from LogReader Service and at which Log Level. But important to know: The LogReaderService sends always all messages to all registered LogListener independent from your configuration !

"Classic" Logging or OSGI Log Services ?

Lets look at the differences between "classic" Java - logging und OSGI - Log Services:

a) Which messages will be logged - and when ?

"Classic" Logging only creates log - messages if the Logger answers "yes" to „should I really log this message at those level for 'the.logger.name'“ ? It depends from the content of your configuration file, what you want to log at which level. If the Logger answers "no" - nothing will be logged.

OSGI Log Services always log ALL messages. The Log Reader Service gets them ALL. The Log Reader Service will inform all Log Listeners about all logged messages. Also the Log Reader Service will cache a configurable amount of messages.
The main task of a Log Listener is to filter the messages and to persist or print them.

b) What will be logged ? And whats the content of the Log Messages

Here you'll see the most important content of a Log Entry:



The different logging frameworks are also using different Log Levels, so they have to be mapped.
The logged Message is a String or will be created from myObject.toString().
MDC (Mapped Diagnostic Context) - a Thread - local Map where you can store context informations, per ex. user info of client sessions.
Marker - a tree of Strings you can mark messages with.

In an OSGI environment its very useful to log informations about the Bundle (and perhaps the Service Reference) where the logged message comes from.
Using OSGI Log Services you'll get this for free. If you're using SLF4J / LOGBack you can also store Bundle- and Service Names. (Using the Marker - more about this later)

c) Whats the best to use ? "Classic" Logging Frameworks or OSGI Log Services ?

Don't ask this question if you're developing an OSGI Enterprise - Application ;-)

Why not ? 

  • You'll never know in advance, which (foreign) projects you'll have to integrate while the whole life-cycle of your business application. 
  • You have to live with 3rdParty Bundles using all kind of logging - frameworks and -strategies. (Sometimes they change it as with Hibernate happened)

But you have to find the answer, HOW to combine and integrate them all without loosing flexibility. If you've solved this issue, then it also doesn't matter what you're using in your own bundles, because your logging architecture consumes it all :-)
Perhaps specific use cases can force you to use 'classic' logging and OSGI Log Services.

Integration of all Logging Frameworks and Log Services



The heart of my solution is SLF4J with LOGBack as native implementation. 


SLF4J (Logback) has already bridges for all 'classic' logging frameworks: this enables you to use bundles logging to Commons-Logging (JCL), Log4J, JDK (java.util.logging) or SLF4J. All logged messages will be transparently routed to LOGBack.

Also all OSGI LogServices - wether Standard or Extended - will be catched from Log Listeners and delegated to SLF4J (LOGBack) delegiert.

So you have ONE place to handle all your logging :-) It depends only from your configuration, if LOGBack prints messages to Console or sends them to a socket (local or remote), to your filesystem, RDBMS or to a LogServer or ... 


(Logging) - Integration of Eclipse Riena


If you're using Eclipse Riena M4 there are currently two small problems to solve:

1. Log4J-over-SLF4J

The bridge Log4J-over-SLF4J only  provides the package org.apache.log4j, but  org.eclipse.riena.core has a dependency to org.apache.log4j.xml. Please change this to "optional" in the MANIFEST.MF:

Import-Package: org.apache.log4j,
org.apache.log4j.xml;resolution:=optional,
org.osgi.framework;version="1.3.0",
org.osgi.service.cm;version="1.2.0",
org.osgi.service.log;version="1.3.0"

2. multiple log entries

Starting with M5 Riena's logging can be configured and its promised that you can switch it all OFF. While using M4 you'll notice two extra messages printed from Rienas LogListener to Console. (Bugzilla 247680)


(Logging) - Integration of EasyBeans OSGI


EasyBeans logging is now transparently routed to LOGBack without any problems. Since some days the Snapshots of EasyBeans 1.1.0 includes Hibernate 3.4, which itself now is using SLF4J. This also causes no problems because LOGBack is native Implementation of SLF4J.


additional informations

This blog is only the first one of a serie about Logging and OSGI. Perhaps it makes sense that you also take a look at my (older) blogs to know the hard way I went ;-)


Links:
  • Simple Logging Facade for Java (SLF4J)
  • LOGBack - Loggingframework, native SLF4J implementation
  • Eclipse Riena (Remote Services, UI enhancements)
  • Eclipse Equinox (OSGI Framework)
  • EasyBeans OSGI (EJB3 Container as OSGI bundles)
  • Hibernate (JPA - integrated into EasyBeans)

How goes it on ?

This blog is only part 1 of the series „Logging in OSGI Enterprise Applications“ giving only a short overview - the following themes will be later discussed in detail with source codee examples - so stay tuned.

  • HowTo registrier OSGI Logging Services
  • Tracking (standard and extended) OSGI Logging Reader Services
  • Adding Log Listeners to LogReader Services
  • HowTo configure LOGBack for OSGI
  • Mapping of LogLevels
  • Details of used Bundles, Manifest - files, dependencies,...
  • Fragment-Bundles
  • OSGI Launch configurations
  • Testing the whole stuff
  • Use of EasyBeans JDBC Pooling to persist messages from LOGBack in RDBMS
  • Performance issues (frameworks, "classic" logging vs. OSGI LogServices)
  • HowTo migrate existing code
  • Useful Eclipse PlugIns (Log4E, LogBack Console)
  • Client-/Server Logging Strategy, Remote Services, MDC - Userinfo...
  • The „black hole“: how to log before the services are ready ?
  • Use of SLF4J Marker to put Bundle- und Service - informations into
  • What happens if other bundles are also using Log Listeners and log messages ?
  • ...

Remark: In my article I'm not covering PAX OSGI Logging. PAX uses Log4J as implementation and also integrates some logging frameworks (JCL, JDK, SLF4J, Avalon). Perhaps you should also take a look at PAX before deciding how to use logging in your OSGI application.

A more detailed complete article is already in work about Logging in OSGI Enterprise Applications“ - and I'll continue this blog series.

Examples with sourcecode will also follow - I'm jst preparing a sample of my  Equinox -based Riena-Easybeans-Server, where the logging of course is an important aspect.



Hopefully you can get some ideas from my experiences and ideas how to solve the logging problem. I promise: if you're developing OSGI enterprise applications - one day you'll run into logging problems, so its better you're prepared.


 in german.

Sunday, September 14, 2008

Eclipse Projects + OSX - some Tips

More and more developers are using eclipse under OSX. Here are two tips from my current experiences:

1. Never name an Eclipse Project *.service

A project name like my.namespace.something.service causes OSX to think its an OSX service and the Finder will show it as an OSX Service and not as folder:



Using right-mouse-click you can look into the "package":



Last months it happens sometimes, that my *.service projects suddenly contain only 0 Bytes and the projects were empty. So I renamed all those projects.

2..DS_Store can confuse P2

Using the Finder of OSX to view folders and files from Eclipse installations causes the Finder to create .DS_Store files.

Suddenly I got on error while starting Eclipse (Bugzilla 247177). Reason was an unexpected .DS_Store file.

Using this command you can remove all .DS_Store files from a whole folder hierarchy:

    find . -name *.DS_Store -type f -exec rm {} \;

(Its always a good idea on OSX to make „.“ - Systemfiles visible, because many important Eclipse files start with „.“: .project, .classpath, ...)


Thursday, September 11, 2008

PDE and MDSD [problem generated code and nested src]

Its a good practice in a model-driven project to separate generated code from manually written code. (Generated code normaly will not be in your cvs / svn)

Eclipse Modeling and openArchitectureWare makes this easy: you can define different outlets in your workflow and XPand templates for generated code. manual code, resources etc.


As result you get a Plug-In Project with some nested src - folders. This is no problem for the Eclipse Java Compiler.



If you try to Export PDE - as deployable Plug-In you run into an error: 



Errordialog:



Logfile:


PDE cannot export Plug-In projects with nested src folders. (s.a. Bugzilla with a small example project from me 241830)

Workarounds: 

  1. Before PDE - Exporting copy the Plug-In Project into a temporary second Plug-In and merge all src - folders into the one and only /src root folder. (Now the workflow while developing and testing isn't as easy as before)
  2. Instead of PDE Export you can use a normal Java - Export as JAR (Loosing the comfort from PDE to auto-detect the Manifest file, versioning ....)
  3. Create some ANT Tasks...

But I'm still looking for the pure PDE solution. Perhaps anyone has an idea how to make PDE happy with nested src folders ?


PDE Target Platform - Rename Bundles [OSX]

Sometimes we have to add "foreign" bundles to our Target Platform where the filenames are not conform to usual Eclipse naming conventions. EasyBeans per ex. uses a minus („-“) to separate the version-number where Eclipse uses Underline („_“).

Problems using „-“ in Symbolic Names are fixed for Eclipse 3.4.1  (Bugzilla 197503). Equinox has no real problems with bundle - filenames separating versions with "-", but its a good idea to rename them. 

If you're using plug-in names in osgi.bundles of config.ini there's a difference: 

Bundle - Filenames separating the version with underline „_“ can be used without the version:
   easybeans-core

But if there's a minus „-“ you have to enter the full filename including versioning: 
   easybeans-core-1.1.0-SNAPSHOT

s.a. Bugzilla 240018.

Of course you can integrate the renaming into your build-process, but sometimes its handy to do it manually. Under OSX the application NameChanger helps. (Freeware)

  1. Download EasyBeans Bundles, actual SNAPSHOT
  2. unzip
  3. open NameChanger
  4. Drag'n'Drop EaysyBeans Bundles into NameChanger
  5. Replace All Occurences of „-1.“ with „_1.“
  6. Click on Rename





PDE Target Platform - Avoid Duplicate Bundles [OSX]

An important part while developing OSGI - Enterprise - Applications is the correct use of PDE Target Platforms. My current ERP project uses:

  • Eclipse SDK
  • Eclipse Equinox SDK
  • Eclipse Riena
  • ....

While creating your Target Platform you'll notice that some downloads contain the same bundles, per ex. downloading Eclipse Platform SDK and Equinox SDK.  

You should know that there are some problems with Target Platforms using duplicates at different locations. Bugzilla 209915, 233096. So its a good idea to avoid duplicates.

If you have installed Apples XCode Tools for OSX, then you can use the application FileMerge:



Whats our goal ? We need all bundles from Equinox SDK not contained in Eclipse Platform SDK.  We choose the following directory locations:



LEFT: plugins folder from Platform SDK
RIGHT: plugins folder from Equinox SDK
MERGE: target plugins folder to get only those Equinox Plug-Ins not already contained in Platform SDK.

Click COMPARE:



EXCLUDE: Identical + Changed Left
EDIT Menu: Select ALL
MERGE - USE RIGHT

Now we can add the merged folder as location to our Target Platform.

Wednesday, September 10, 2008

PDE and 3rdParty Bundles in OSGI Enterprise apps

If you're developing an OSGI based Enterprise Application you'll always reach a point where you have to integrate external libraries, bundles or whole projects. In many cases PDE tooling will be your friend.

You have to watch some rules to make life easier - for you and others using your bundles. I already talked about this in previous blog entries. Hopefully it will help you to avoid chaos in your OSGI environment.

1. JAR - Files as Bundles

As a good citizen of OSGI world there's the first rule: 

Rule 1: 
Always put dependent JAR Files in separate bundles and describe the dependencies in your Manifest file. 
Don't hide those JARs in your own bundle. 

Then its much easier to re-use bundles or to let your bundles play together with others.

PDE makes it very easy to create bundles (plug-ins) from JAR - Files: Select New - Plug-In Development - Plug-in from existing JAR - archives, choose the JAR File - and thats it :-). 
Attention - please use this comfortable function as last of your steps ! At first follow the next rule for good OSGI citizens:

Rule 2: 
If a Bundle for your dependent JAR File already exists in one of the Bundle Repositories - then choose this. 
Don't create your own bundles for existing ones.

How do you know, if there's already a bundle ? Here's my way to search bundles:

  1. Does the bundle exist in the SpringSource Enterprise Bundle Repository ? SpringSource is my first choose, because all bundles and dependencies are described there in detail. A great thanks to the SpringSource Team for this great work.
  2. Does the bundle exist in the Eclipse Orbit Repository ? You can find an overview here.
  3. To be sure also search for the bundle at OSGI (look at OBR Bundle Repository).
  4. Only if all search results are negative, I'm creating my own bundle with help of PDE as descibed above. If its a common JAR - File used in many projects, then I create an entry into SpringSource JIRA "wishing" to have this bundle there. Some time ago I was looking for bundles of Drools Rule Engine, but nothing exists in any of the repositories. So I put an entry into SpringSource JIRA. Some days later: „Mission completed“ - if you're now looking for it you'll find per ex.: Drools Rules Engine Core.

2. Using "foreign" Bundles

Great - with the help of the repositories of PDE - Tooling we got all the dependent bundles providing the needed functionality and APIs. Now we can integrate them into our own OSGI Project.

Analyzing other projects and bundles in many cases I found, that the easiest way was used: Need a bundle ? Put a dependency with Require-Bundle. And because its so fast and easy re-export it simply hitting „Re-Export this dependency“ in Manifest editor.

To get a clean OSGI architecture there's something more to think about ;-)

My next rule to watch follows. I know that there's some controverse discussion about required bundles vs. importing packages. But from my experiencies you should do this:

Rule 3: 
If possible use Import-Package to resolve your dependencies. 
Export only your "public" packages  - no internal. 
Use Require-Bundle only to resolve dependencies inside your own „universe“, not against common bundles. 
Always version Require-Bundle, Import-Package und Export-Package.

Require-Bundle always has a dependency to a bundle with a specific name. You cannot change an Eclipse Orbit Bundle (per ex. org.apache.commons.logging) with a SpringSource Bundle (com.springsource.org.apache.commons.logging) if you're using Require-Bundle - only using Import-Package

Import-Package isn't dependent from the name of the bundle, so its more flexible. Of course its more work to look at your packages and decide which you need to import or to export compared to a one-liner with Require-Bundle

One example: Eclipse Riena needs a special Hessian Bundle because of Eclipse Buddy Policy. If you have a bundle where Require-Bundle points to another Hessian bundle you cannot use the one Riena needs. If you're using Import-Package you can avoid much trouble.

I have some more rules I'm watching to work easier with PDE:

Rule 4: 
If a bundle itself contains packages inside the bundle and exports them, never put these packages also into the Manifest as imported packages.
This can cause PDE to detect cycles and then some functionalities of PDE tooling don't run as expected.

s.a. Bugzilla 246615, 246617 and 208011.

Rule 5: 
Before deploying of a bundle as plug-in be sure the Package-Uses are re-calculated. 
Wrong Package-Use entries for exported packages can stop PDE to export your Plug-In.

s.a. Bugzilla 246615.

Rule 6: 

Avoid nesting  JAR - Files - better use multiple bundles.

s.a. Bugzilla 157375 - esp. comment #31.

Workaround: If a dependency to a „foreign“ binary bundle with nested JAR Files is causing PDE Build - problems, most time it helps to load another plug-in exporting these classes into the workspace.
Attention: You need this plug-in only to build / compile your bundle not for Runtime or OSGI Launch Configurations, because Equinox has no problem using bundles with nested JAR Files.

If you watch these DOs & DON‘Ts, then I'm sure you have less trouble and chaos and also your bundles itself can easy be integrated into foreign OSGI projects.

3.Integration of whole ("foreign") OSGI Projekts 

Sorry, but the reality isn't so easy as described above building complex OSGI Enterprise applications. You have to live with other projects not following those rules.

As an example try to integrate the OSGI EJB3 container from EasyBeans. EasyBeans contains some different components, utilities, an agent and a core bundle.

Not watching  Rule 1 and Rule 2:
bundle org.ow2.easybeans.core contains uncount JAR Files (the core bundle has a size of 12 MB). Many of these JAR Files are already available as bundles in OSGI Repositories. This makes it very hard to work with the core bundle and to let your own architecture clean. The EasyBeans team knows about this, so hopefully in the future this will become better.

Not watching Rule 4 and Rule 5:
org.ow2.easybeans.core causes problems with PDE Dependency Analyzing: PDE reports cycles and wrong package-uses. If only using the easybeans.core bundle in runtime or OSGI launch configurations, all works perfect. 
Problems arrive if an own bundle has dependencies to org.ow2.easybeans.core: PDE cannot export the bundle as Deployable Plug-In, because cycles and wrong Package - Uses are reported. (s.a. Bugzilla 246615)

Workaround to export your bundle with PDE tooling:

At first load bundle org.ow2.easybeans.core as Source Project into your workspace.

  1. PDE reports incorrect Package-Uses of org.ow2.easybeans.core if you try to export your bundle as deployable plug-in. Open MANIFEST.MF of org.ow2.easybeans.core bundle from workspace, tab Runtime - Exported Packages re-caclulate Uses. Save MANIFEST.MF and try again to export your bundle.
  2. Now PDE detects the cycles. Again open MANIFEST.MF, tab Dependencies, Dependency Analysis „Find unused Dependencies“ and remove all selected. Save MANIFEST.MF and try to export again.

Now you can export your bundle :-)

Remark: PDE is happy with this manipulated easybeans.core bundle - but never try to use this in runtime or from OSGI launch configs ! 

Problems with bundle - filenames:

EasyBeans uses filenames like 
    easybeans-component-hsqldb-1.1.0-SNAPSHOT
Eclipse uses filenames like 
    easybeans-component-hsqldb_1.1.0-SNAPSHOT

Did you notice the difference ? Eclipse uses underlines (_) before the version (1.1.0) and EasyBeans uses minus (-).

I'm always replacing -1.1.0 by _1.1.0 after downloading from EasyBeans. This makes some things easier, per ex. in bundle.info of config.ini I can use the plug-in - name only. Without replacing I always have to enter the whole filename, which means I have to change the config.ini for all version-changes, because Equinox cannot find the version number with all these "-" (Bug JIRA).


Problems with Bundle - Symbolic Names:

PDE has a problem using "-" in Symbolic Names. (s.a. Blog A dash of legacy from Chris Aniszczyk). 

EasyBeans contains some Util Bundles, where the symbolic name contains "-" (per ex. org.ow2.bundles.ow2-util-event-api). If you load such bundles into your workspace, they are marked as error (Bundle symbolic name contains illegal characters.  Legal characters are A-Z a-z 0-9 . _). You have to change the symbolic name.

Result:

Hopefully my rules, solutions and workarounds will help others fighting with OSGI bundle - dependencies.
If you're noticing problems with logging, please read my blog entries about "Logging in OSGI Projects".

Follow - Up:
Some more blogs are work-in-process and will follow soon to demonstrate the use of EasyBeans 1.1.0, Eclipse Riena M4 and Equinox 3.4 in a small example project.