2

I have been working on demo example where JPA would be used with OSGi.

The thing is, I am able to start/stop the service after bundling however I am not able to get the serviceReference. Due to this my JPA implementation is not getting executed.

Following is the code:

Activator.java

package manning.osgi.jpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

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

public class Activator implements BundleActivator {

public void start(BundleContext context) throws Exception {
    LoginEvent loginEvent = new LoginEvent();

    // Set login event...
    loginEvent.setUserid("alex");

    try {
        ServiceReference [] serviceReferences =
                context.getServiceReferences(
                        EntityManagerFactory.class.toString(),
                        "(osgi.unit.name=LoginEvent)");

        System.out.println("Service References Created");

         if (serviceReferences != null) {
             EntityManagerFactory emf = 
                 (EntityManagerFactory) context.getService(serviceReferences[0]);

             EntityManager em = emf.createEntityManager();

             persistLoginEvent(em, loginEvent);
             System.out.println("Transaction started");

             loginEvent = retrieveLoginEvent(em, loginEvent.getId());
             System.out.println("Transaction completed");

             em.close();
             emf.close();
         }

    } catch (Exception e) {
        System.out.println("Exception"+e.getMessage());
    }

}

private void persistLoginEvent(EntityManager em, LoginEvent loginEvent) {
    em.getTransaction().begin();

    em.persist(loginEvent);

    em.getTransaction().commit();
}

private LoginEvent retrieveLoginEvent(EntityManager em, int id) {
    em.getTransaction().begin();

    LoginEvent loginEvent = em.find(LoginEvent.class, id);
    loginEvent.getUserid();
    loginEvent.getId();
    loginEvent.getTimestamp();

    em.getTransaction().commit();

    return loginEvent;
}

public void stop(BundleContext context) throws Exception {
}

}

LoginEvent.java

package manning.osgi.jpa;

import javax.persistence.*;

@Entity
public class LoginEvent {

@Id
@GeneratedValue
private int id;
private String userid;
private long timestamp;

public int getId() {
    System.out.println("\nID: "+this.id);
    return this.id;
}
public String getUserid() {
    System.out.println("\nUser ID: "+this.userid);
    return this.userid;     
}
public void setUserid(String userid) {
    this.userid = userid;
}
public long getTimestamp() {
    System.out.println("\nTime Stamp: "+this.timestamp);
    return this.timestamp;
}
public void setTimestamp(long timestamp) {
    this.timestamp = timestamp;
}
}

persistence.xml

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="LoginEvent">
    <class>manning.osgi.jpa.LoginEvent</class>        
      <properties>
        <property name="javax.persistence.jdbc.driver"
            value="org.apache.derby.jdbc.EmbeddedDriver"/>
        <property name="javax.persistence.jdbc.url" 
            value="jdbc:derby:derbyDB;create=true"/>
    </properties>
</persistence-unit>
</persistence>

MANIFEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: OsgiDemo
Bundle-SymbolicName: manning.osgi.jpa
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: manning.osgi.jpa.Activator
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: javax.persistence,
 org.osgi.framework;version="1.3.0"
Bundle-ActivationPolicy: lazy
Require-Bundle: javax.persistence;bundle-version="2.1.0"

The code is compiling but as the serviceReference is null I can't progress. I rechecked the persistence-unit name and its correct.

Can anyone plz help me out what I am missing here. Thank you.

Amrit
  • 2,295
  • 4
  • 25
  • 42

1 Answers1

3

In your Activator you cannot be sure that the ServiceReference you need is already available. It may happen that your bundle starts before the one that registers that service. It is also possible that the other bundle fails to start so the service will not be registered.

In case you want to code a lot, you can create a ServiceTracker inside your start function and do the same in the addingService function of the tracker as you did in the start function of the BundleActivator.

In case you want to work less, use Declarative Services (many tutorials are available on the net). There you can define that your Component should not start until the OSGi service you need is available.

Btw.: You should call unGetService if you used getService(serviceReference) function.

V G
  • 18,822
  • 6
  • 51
  • 89
Balazs Zsoldos
  • 6,036
  • 2
  • 23
  • 31
  • It's been almost a year since I did OSGi. Forgot about the `ServiceTracker`. I guess this might be the issue. And yes, +1 for DS. – Rohit Jain Nov 22 '13 at 12:22
  • yea you may be right about the services not getting started before I register. However I can't seem to fix it somehow. I learnt that http://en.wikipedia.org/wiki/OSGi_Specification_Implementations says JPA is implemented in Aries or Gemini. I have been using Eclipse & Equinox for my JPA example. – Amrit Nov 28 '13 at 05:57
  • Aries and Gemini does not implement JPA. They implement an extender that picks up bundles with persistence.xml and create new EntityManagerFactory OSGi services based on a JPA engine. More specifically, they implement the "Java Persistence API" chapter of the OSGi enterprise specification. If you have all aries bundles that you need, you should see an EntityManagerFactory service. How you use that service is not JPA related but more OSGi stuff. E.g. Yoou can inject it into your class with DS or Blueprint. – Balazs Zsoldos Nov 28 '13 at 09:57