Monday, November 17, 2008

HowTo Build an OSGI Enterprise Server: EJB3 Container

This entry of my blog series „HowTo build an OSGI Enterprise Server“ will talk about the „EJB3 Container“ managed by EasyBeans. EasyBeans uses by default Felix as OSGI Framework - this blog series describes how to use it all under Eclipse Equinox together with Eclipse Riena.

You have to follow some rules how to start the OSGI application: start - levels, start - order, automatic-start ... Please read important instructions in chapter „Server starten“. A short overview:



Our OSGI Enterprise application automatically starts a „Server Agent - Bundle“ - this agent contains an OSGI Service Tracker watching if EasyBeans initializes all EJB3 Container to see when all is ready.

We also start our domain-specific „Server Bundles“ which are tracking to see if our ServerService is registered from „Server Agent“ Bundle.


Server - Agent - Bundle and Server - Bundles




Our (domain-specific) „Server - Bundles“ and the „Server - Agent - Bundle“ are started automatically using Default - Start - Level (in our example Level 3).

The „Server - Bundles“ are waiting until a RienaEasyBeansServerService signals, that our Server with Riena- and EasyBeans - Functionality is available.

The most important dependencies of our „Server - Agent“ - Bundle:



The „Server - Agent“
  • tracks Services from EasyBeans using an EasybeansServiceTracker
  • registers Remote - „Business - Interfaces“ for Riena - Remoting
  • registers RienaEasyBeansServerService when or server is available

EasybeansServiceTracker - Filter

An OSGI ServiceTracker should only track needed Services - so we have to define a Filter used as Parameter creating a new ServiceTracker. The Filter:

(|(objectClass=org.osgi.service.cm.ManagedServiceFactory)(objectClass=org.ow2.easybeans.api.EZBContainer)(objectClass=org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent)(service.pid=*RemoteManagerI*Bean))

What kind of OSGI Services we'll get using this Filter ?


ManagedServiceFactory:

EasyBeans registers for each EasyBeans Component a Service of Type ManagedServiceFactory:

{org.osgi.service.cm.ManagedServiceFactory}=
{service.pid=org.ow2.easybeans.component.carol.carolcomponent,..
Registered by bundle:
...easyBeans/bundles/easybeans-component-carol_1.1.0-...jar
Bundles using service:
.../org.eclipse.equinox.cm_1.0.0.v20080509-1800.jar
.../org.ekkehard.server.agent_1.0.0.jar

Tracking these Services we can test if all EasyBeans Components are correct initialized.

EZBContainer:

After successfully processing our „EJB - Bundles“ and „PersistenceContext - Bundles“ from EasyBeans a Service of Type EZBContainer is registered:

{org.ow2.easybeans.api.EZBContainer}={service.id=103}
Registered by bundle: .../org.ekkehard.foo.datamanager.bean_1.0.0.jar
Bundles using service:
.../easybeans-core_1.1.0-M3-SNAPSHOT.jar
.../org.ekkehard.server.agent_1.0.0.jar

Tracking these Services we know, that EasyBeans has created an EJB3Container for our Bundle - and if its a „PersistenceContext - Bundle“ then we also know, that Hibernate has done all the Mapping and Binding.

JDBCPoolComponent:

EasyBeans JDBCPoolComponent registers always after initializing a DataSource an OSGI Service of Type JDBCPoolComponent:

{org.ow2.easybeans.component.api.EZBComponent,
org.ow2.easybeans.component.jdbcpool.JDBCPoolComponent}=
{... jndiName="foo_data_source_hsql"....

Using the Property jndiName we can test if our DataSource is available.

service.pid:

We also filter Services containing a service.pid of our pattern for Remote - Business - Interfaces: „*RemoteManagerI*Bean“. The pattern depends from your naming schema.

Tracking those Services will give us OSGI Services of Type ManagedService. The we do some additional testing to see if some Properties are set from EasyBeans. If true, we know that its a ManagedService created by EasyBeans for one of our @Remote - „Business - Interfaces“.



Now we can register this @Remote - „Business - Interface“ for Riena Remoting, to provide a Riena Published Endpoint for our Rich Clients.

This is also the reason why the „Server - Agent - Bundle“ needs Package-Import-Dependencies to our „Business - Interface - Bundles“ - if you dont use Riena, then you dont need these dependencies.


RienaEasyBeansServerService

If all tracking was successfully, then our „Server - Agent - Bundle“ registers an RienaEasyBeansServerService as OSGI Service. Because this Service will also be registered as Riena Remote Endpoint, our „Server - Bundles“ and also our „Rich Client - Bundles“ can track if the Server of a specific domain is live and ready-to-go.

When knows the „Server - Agent“ that all was successfully processed ?
  • All EasyBeans Components are initialized
  • All DataSources are avilable
  • All EJB Container are available
There are some special tricks how to track and test and start bundles - but this will be part of the next blog.

There's an this index of this blog series in the column right beside the blog entries.

blog in german

Wednesday, November 12, 2008

HowTo Build an OSGI Enterprise Server: Entity- and EJB- Bundles

This part of the blog series „HowTo build an OSGI Enterprise Server“ will take a look at the different types of bundles we provide to the EJB3 container. The next chapter „EJB3 Container“ will show you how to use an OSGI ServiceTracker to start and initialize all the right way.


How to divide Entities and EJBs in Bundles

BTW: you should have knowledge about EJB3 and Annotations. The structure used in this server is only an example and your implementation perhaps is different. We can talk about these issues later after publishing source code. Also you can use Eclipse Link as JPA provider instead of Hibernate - EasyBeans can work with both.

We're using following types of bundles:

  • Entity - Bundles
  • EJB - Bundles
  • PersistenceContext - Bundles 
  • Business Interface - Bundles 


Entity - Bundles

@Entity, @Embeddable
You can use as much Entity - Bundles as you want - perhaps structured vertical for your different domains. These Entity - Bundles will also be used from our Rich Client, so - if you have bundle dependencies only used at server-side, make them optional.


EJB - Bundles

@Stateless and  @Stateful Beans, implementing Business - Interfaces (@Local, @Remote) depending from your requirements. 
These Bundles have dependencies to your Entity - Bundles and to the Business - Interfaces. 
Other EJBs from your PersistenceContext - Bundles can be injected like:
@EJB(mappedName) Business - Interface
The EJB - Bundles will not be used from Rich Client.

Remark: mappedName must be used at the moment, EZB cannot found the corresponding Business - Interfaces, if they are in different bundles (JIRA EZB-322)


PersistenceContext - Bundles

@Stateless Beans, containing a PersistenceContext (EntityManager) and - depending from your use-cases - implementing Business - Interfaces (@Local, @Remote).
@PersistenceContext(unit-name) points to your Persistence - Unit.
Each PersistenceContext - Bundle has a persistence.xml with attributes for the persistence-unit and also jta-data-source.
PersistenceContext - Bundles need package-imports of the used Entities and  implemented Business - Interfaces.
PersistenceContext - Bundles will not be used at Client-Side.

Remarks: 
  1. All EJBs, belonging to a peristence-unit, must be in ONE bundle at the moment. (JIRA EZB-294)
  2. The Beans must have an EJB3.mappedName attribute: @Stateless(mappedName), otherwise because of a bug from EasyBeans (JIRA EZB-322) injected @EJB won't found them.
  3. Inside the persistence.xml all Entity- and Embeddable must be listed as class entries. EasyBeans should found the classes itself because of Annotations, but there's a bug if Entities and EJBs are in different Bundles.


Business Interface - Bundles

@Local, @Remote
The Business - Interface - Bundles can be structured and separated as you want - perhaps for different sub-applications or domains or...
These Bundles will also be used from your Rich Client.


EasyBeans Configuration

EasyBeans needs some configuration - data. If you're using an OSGI Framework Configuration you can add a VM argument: 
-Dorg.ow2.easybeans.osgi.conf.dir=${workspace_loc}/config/easybeans/config 
In this config folder you must store the easybeans.xml.
This easybeans.xml contains jdbcpool jndiName entries for each of your  Data - Sources. These values are identical with the jta-data-source, described at your  Persistence Unit inside persistence.xml of our PersistenceContext - Bundles.


Remark: The EasyBeans JDBCPool - Component must register first all Data - Sources, before you can start your PersistenceContext - Bundles. s.a. chapter „EJB3 Container“ for details on this.


openArchitectureWare - always can help if you're in trouble

This project is model-driven - details about it will be described in another blog series. Here are some small examples showing you, why I never will miss  openArchitectureWare in a project lead by me.


EasyBeans should recognize @Entity and @Embeddable automagically because of annotations - but it doesnt work through borders of bundles, so all @Entity and @Embeddable - classes have to be listed in your persistence.xml - in my ERP project this means more then 800 classen - and the data model isn't static and grows or changes depending from new use-cases and requirements.

But thanks to openArchitectureWare (oAW) we only need some lines in a template to get the needed output into the persistence.xml:

automatically all was generated from oAW and is in sync with your entity data model:

Another example: EasyBeans should be able to inject @EJB MyBusinessInterface correctly. But because of a bug this isn't possible if Business Interfaces are in another bundle and so we need the @EJB.mappedName attribute.

But with oAW its also easy: insert some text into a XPand - Template to add this attribute:

... and in your Business Interface:

Now all Beans get the mappedName attribute, the Business Interfaces get a Constant with this mappedName so you can inject easy:
@EJB(mappedName = MyInterface.EZB_MAPPED_NAME) MyInterface mi = null;

These are positive side-effects of model-driven development: developing of workarounds in hundredrs of classes are funny ;-)

BTW: my whole complex ERP - project would not be possible to be realized from me alone without oAW. You'll hear more about this in another blog series - and of course its your decision if you work model-driven or not - I only can show you my way of working.

 
 blog in german.

Tuesday, November 11, 2008

HowTo Build An OSGI Enterprise Server: Introduction

If you followed my blog series „Logging in OSGI Enterprise Applications“, you probably know that logging is only one small but important aspect of an OSGI Enterprise Server.

This new blog series „HowTo Build An OSGI Enterprise Server“ will give you tips from my experiences how to build and configure an OSGI server, how to structure your project and bundles and how to make it all run.

Main parts of the server are:

  • Equinox (OSGI Framework)
  • Riena (OSGI RemoteServices, ObjectTransactions)
  • EasyBeans (OSGI EJB3 Container, Hibernate JPA)

There will also be a rich client:

  • Equinox (OSGI Framework)
  • Eclipse RCP
  • Riena (OSGI RemoteServices, ObjectTransactions, UI: Ridgets) 

(Clients for mobile devices and web will follow.)

Not only the Runtime Platform is important - the whole project is model-driven:

  • Eclipse Modeling (EMF, UML2)
  • openArchitectureWare - oAW (Workflow, XPand, Xtend)
  • Magicdraw (UML, DSL, oAW Integration)

Server, Client, oAW Templates, MagicDraw Custom DSL Editor will be published as Open Source (EPL) and are used as core of an ERP - Business Solution.

Before giving an overview of the project and then start with chapter „Installation“ I'll jump to chapter „EasyBeans as OSGI EJB3 Container integrated with Equinox“ because I know some are waiting for this.

From readers of my last blog series I learned that its not always easy to read the entries in right order - to help you I'll always update an index of the blog series. You'll find this index in the column right beside the blog entries.

I hope to help some others with this new blog series and I'm always thankful for your feedback.

Later on blog series will follow "HowTo build an OSGI Rich Client" and also "Modeling OSGI Client - Server Applications". 


 blog in german.

Friday, October 31, 2008

Index BlogSeries Logging in OSGI Enterprise Applications

I got responses that its not easy to read the blog series
"Logging in OSGI Enterprise Applications" in chronological order.

So here's the index:

Logging in OSGI Enterprise Applications, Part 5

This (fifth) part of my blog series "Logging in OSGI Enterprise Applications" will show you some important elements of configuring the logging framework LOGBack we use as SLF4J implementation:


I dont want to talk about the configuration of a logging framework itself - you should be familiar with this. If you're using LOGBack inside an OSGI Enterprise Application there are some special things to watch and problems to solve.

If we're logging in a non-OSGI Java Application we normaly want to know which class logs the event. Logging from an OSGI Enterprise Application its also important to know which bundle causes the LogEvent. Using OSGI LogServices you also have this information from BundleContext..

Its a good practice to name the Logger with the class name - normaly as static Logger defined in each class. This works with all logging frameworks like Log4J, Commons-Logging, java.util.logging or SLF4J.

Using SLF4J as Logging API you can also describe the source of the Log Event more detailed with:
  • MDC (Mapped Diagnostic Contexts)
  • Marker 

MDC is implemented by Log4J and LOGBack. MDC is great to store informations from a client user session: per ex. Username, IP etc. Its a Map and you're free to store what you like. To  access these informations in the Layout of an Appender is easy: 
    ...N:%X{username}... 
produces
   ...N:JohnDoe...
The LOGBack User Manual chapter 7 (here) explains it in detail and gives you some examples.

Marker and Bundles

Marker are part of the SLF4J API and they mark (as the name says ;-) Log Messages. At the moment only LOGBack implements Marker.  
From the MarkerFactory for a given String we always get the same Marker: 
    Marker marker = MarkerFactory.getMarker("MyMarker");

Marker can reference other Marker - so you can build an object graph of Marker:
    Marker special = MarkerFactory.getMarker("special");
   special.add(MarkerFactory.getMarker("init"))

In our OSGI Enterprise Application we're using Marker to log the Name of the bundle.


For each bundle we define once (per ex. in the Activator):

    private static final Logger logger = LoggerFactory.getLogger(MyActivator.class);
    public static final String ID = "my.bundle.symbolic.name";
    public static final Marker bundleMarker = createBundleMarker();
    private static final Marker createBundleMarker() {
        Marker bundleMarker = MarkerFactory.getMarker(ID);
bundleMarker.add(MarkerFactory.getMarker("IS_MARKER"));
return bundleMarker;
    }

In all the other classes of a bundle we define:

    import static MyActivator.bundleMarker;
    private static final Logger logger = LoggerFactory.getLogger(Foo.class);

Then the logging statements are looking like:

    logger.debug(bundleMarker,"This is my {} message",xyz);

Remark: LOGBack replaces {} with xyz. toString(). More details later.

To get the marker in the logging - output we can simply use
    ... %marker ... 
in the Layout of an Appender. 

In our application we want to test if a Marker is a BundleMarker and then handle formatting the output different, per ex.: 
    ... - [B:my.symbolic.bundle.name] ...

To do this we have to extend ch.qos.logback.classic.pattern.ClassicConverter and overwrite the methode public String convert(LoggingEvent le).

In our LOGBack configuration (logback.xml or logback-test.xml) we have to insert a new ConversionRule:


then we can use it in the Layout of an Appender:
    ... %bundle ...
and we get as output
   ... - [B:my.symbolic.bundle.name] ...
or an empty String if the Marker is no BundleMarker.


Fragment Bundles

But thats not all - because the logback.classic Bundle doesnt know our BundleConverter class we need a Fragment-Bundle:


You remember: We already use another Fragment to use our configuration file from Logback Core Bundle:



Remark: perhaps you have noticed that the Manifest files above are using logback Version 0.9.11: there are new versions of SLF4J (Download Version 1.5.5) and LOGBack (Download Version 0.9.11). Because at the moment they are not found from SpringSource EnterpriseBundleRepository we have to build them by ourself. How to do this is explained in part 2 of this blog series.

Logoutput twice

It looks so good: we catch all LogEvents from all Logging Frameworks used from other Bundles and also from OSGI LogServices. But it can happen that you found some messages twice in your log output. What happens ? If you're using per ex. Eclipse Riena M4 you got messages twice:

Riena uses Listener to catch OSGI Logservices and logs them using Log4J. Log4J will found the way to our SLF4J / LOGBack implementation. So long so good.
But our own Logging Bundle org.ekkehard.osgi.over.slf4j also catches OSGI Logservices and loggs them using SLF4J / LOGBack.
And now we got some messages twice.

The good news first: in some days Riena will publish Milestone M5 and then you should be able to switch these Listeners from Riena-Logging off.
Because it can happen every day again using other 3rdParty bundles, here's the solution. We need an entry in our LOGBack configuration file logback.xml:


This will hide those output from org.eclipse.riena. 

Riena uses Equinox Extended OSGI Logservices, which contain an own Logger. We catch those ExtendedLogEvents and log the message using the Loggername from ExtendedLogEntry. To distinguish Logging - Output from our Listeners we add a prefix:


Now we know where the Logging - Output comes from and as a side-effect its easy to log all LogEvents originally logged from Equinox ExtendedLogServices per ex. at DEBUG Level:


Here's an example logging output catched by our Listener and logged to LOGBack:

23:25:41.846 DEBUG [X.o.e.r.c.publisher.ServicePublishBinder] - [B:org.eclipse.riena.core] service endpoints count: 792

ExtendedLogEntry uses this as Loggername:
    org.eclipse.riena.communication.publisher.ServicePublishBinder
We add the prefix "X."
You also see a Bundlename (from our BundleConverter)
    org.eclipse.riena.core
We got the name from Context of the catched ExtendedLogEntry: 
    getBundle().getSymbolicName()

Using Marker from LOGBack is an easy way to get the information of the Bundle logging the event and also not to loose the Bundlename if rooting LogEvents from OSGI LogServices to SLF4J/LOGBack.

What happens next ?

This blog series isn't finished, but we already talked about the most important informations about Logging in OSGI Enterprise Applications. Of course I'll continue this series next months because there are some more aspects to look at in detail. But expect next blog entries in a time-frame of 2-3 weeks for each.

Blog Series "Logging in OSGI Enterprise Applications":

Perhaps some of my older blogs about Logging und OSGI are also interesting:


New blog series coming soon

Now I'll also starting a new  blog series :

„HowTo build an Equinox-Riena-EasyBeans-OSGI-Server“. 

After working through that blog series you'll get a complete server as Open Source (EPL) to try it out by yourself. This server of course also contains all of the logging aspects I talked about.


this blog in german