In an OSGi environment, how are the classpaths and classloaders set up? - jpa

I'm confused about class visibility in OSGi. I'm running Apache Felix and loading the following bundles:
the antlr, asm, jpa and core bundles from eclipselink
an OSGi-fied jar for javax.persistence 1.99
an OSGi-fied jar with the com.mysql.jdbc driver
a bundle of my own that contains annotated entity classes and a persistence.xml
another bundle of my own that calls Persistence.createEntityManagerFactory(String, Map)
Now, what I'm confused about is which bundle must be able to see the MySQL driver. I thought this would be the bundle creating the EntityManagerFactory, but I get ClassNotFound errors when I import in that manifest. Next, I tried importing it from the eclipselink jpa bundle's manifest, but wrong again. Only when I import it from the manifest of the bundle containing the persistence unit (entity classes and persistence.xml), it works.
So, seemingly the database driver is looked up by the clasloader for the PU's bundle, but that doesn't make sense to me. What's going on?
I can't seem to find a straightforward documentation for this. These slides give some hints, but aren't exactly comprehensive.

I'm familiar with the OSGi classpath issues around Hibernate and JDBC and I can give you my reasoning on what's happening based on the slides you linked to.
I'm assuming you've added the JDBC driver entry to the persistence.xml inside your PU bundle?
EclipseLink is using the extender pattern to do work on the PU bundle's behalf. The extender is listening for bundles starting, checking if they have a persistence.xml and then doing the work of setting it up. It expects the PU bundle to import all the types you may reference in the persistence.xml, including the JDBC driver.
Think about it. The EclipseLink bundle won't import every known JDBC driver (and it shouldn't) - only your bundles can know which database driver they need, so it's reasonable to expect your PU bundle to import the JDBC driver class.
You shouldn't need to modify the manifests of the 3rd-party libraries if they are already OSGi-ified, such as EclipseLink.

I found this pdf to be quite informative regarding classloading:
http://www.martinlippert.org/events/WJAX2008-ClassloadingTypeVisibilityOSGi.pdf

Related

Packaging JPA entities in a jar inside a Spring Boot application

I am refactoring a JEE REST (using JAX-RS 2.0) application as a Spring Boot application. My old app is packaged in a .war and has a jar file with entities and the persistence.xml configuration file for JPA. This jar is copied into WEB-INF/lib directory. I know Spring JPA works a different way and I don't use persistence.xml now but I wonder if I can package my JPA entity classes in a jar and include them in my Spring Boot apps just like I am doing now. This way I can easily reuse that jar in different Spring Boot Applications.
I'm pretty certain you can do this since I have done the same on one of my projects very recently. The only thing you need to do is make sure that you add an #EntityScan annotation on your main Spring Boot config class with the base package of your entities in the JAR.
#EntityScan("my.external.jar.entity.package")
Spring Boot doesn't really care whether the JPA entities are packages as a separate jar or included into the application. Its a runtime framework and in runtime classes can be loaded from the jar (it should reside in BOOT-INF/lib or 'directly' from the *.class files in the spring boot artifact.
Now there is a rule in spring boot, that says that it will scan for beans (including entities) only in the package where your "main" class resides or under it. This is done in order to avoid long process of analysis of, say, third-party classes that you might use. These third-party classes are usually not spring aware at all, at certainly do not contain any spring beans.
Example:
Say, you place your "main" class (the one annotated with #SpringBootApplication) in the package: com.mycompany.myapp
In this case, the following packages will be scanned (just a couple of examples):
com.mycompany.myapp
com.mycompany.myapp.web
com.mycompany.myapp.services.bl
com.mycompany.myapp.whatever.doesnt.matter
...
The following packages won't be scanned however (again, examples, not the full list):
com.mycompany
com.anothercompany
org.hibernate
If you want to to "alter" this default rule and place the entities in the package that doesn't adhere this convention, for example com.mycompany.jpa.entities then you should indeed use #EntityScan annotation as our colleagues have already suggested.
You can read about this topic here. You might also need to get familiar with #EnableJpaRepositories if you're using spring data but, while related, its a different topic.
In my case I had this problem, and after importing the library in the application's pom.xml, in the SpringBoot Project Main class, insert an #EntityScan annotation with the first package and *. Like this: #EntityScan ("br.*")

EclipseLink Annotations cannot be resolved

I'm trying to create a simple EclipseLink POC. Unfortunately, it doesn't seem to include important, basic classes within the JAR.
For example, the following fails within eclipse (and eclipselink is definitely on the build path): import javax.persistence.Id. Should I have a basic-JPA-functionality jar as well? Are annotations stored somewhere else within eclipselink (I've looked, can't find anything)? What am I missing?
Thanks
API part is missing. Name of jar is javax.persistence_1.0.0.jar. In EclipseLink 2.4.1 (http://www.eclipse.org/eclipselink/downloads/index.php#2.4 Installer zip) download it is located to eclipselink/jlib/jpa/javax.persistence_1.0.0.jar.

javax.persistence.PersistenceException

i have a problem with a JPA project that is connected with a EE project, i have done the tests (JUnit 4) for the DAOs in a source package with a persistence.xml only for this test units.
when i'm going to test them they get me this error, like if the unit tests can not found the persistence provider.
please some one help me.
thank you
Persistence Provider can't be found refers to JPA provider Jar file not being included into your test environment. Make sure JPA provider (Hibernate/ OpenJPA or whatever is provided with your app server) jar is available in classpath from where your test case reads dependent libraries.

Using EclipseLink 2.3.0 from Target

I want to use EclipseLink 2.3.0 (as provided with Indigo, resp. the Update Site target provided on http://www.eclipse.org/eclipselink/downloads/) in an Eclipse RCP application.
If I include the EclipseLink libraries specifically in a Plug-In by means of creating a lib folder, stuffing them all in and adding them to the classpath, all the Entities I have in the Plug-In are being found and registered.
If I however switch to using the target distributed EclipseLink Implementation, by adding javax.persistence and org.eclipse.persistence.jpa, the connection to the database is readily built... however NONE of the Entities are found! The occuring message always is:
[EL Warning]: The collection of metamodel types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units. Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element
My persistence.xml however denotes the respective class, as it is being found when I use the manual libraries! This is rather confusing, any hint on this? :) THX
Take a look at the EclipseLink OSGi examples on the Eclispe wiki for details on how to develop in PDE, how to enable byte code weaving, and an RCP example.
http://wiki.eclipse.org/EclipseLink/Examples/OSGi
--Shaun

How to use 3rd party libraries in glassfish?

I need to connect to a MongoDB instance from my EJB3 application, running on glassfish 3.0.1. The Mongo project provides a set of drivers, and I'm able to use them in a standalone Java application.
How would I use them in a Java EE application? Or maybe better phrasing: how would I make a 3rd party library available to my application when it runs in an EJB container?
At the moment, I'm getting a java.lang.NoClassDefFoundError when deploying a bean that
tries to import from the library:
[#|2010-03-24T11:42:15.164+0100|SEVERE|glassfishv3.0|global|_ThreadID=28;_ThreadName=Thread-1;|Class [ com/mongodb/DBObject ] not found. Error while loading [ class mvs.core.LocationCacheService ]|#]
[#|2010-03-24T11:42:15.164+0100|WARNING|glassfishv3.0|javax.enterprise.system.tools.deployment.org.glassfish.deployment.common|_ThreadID=28;_ThreadName=Thread-1;|Error in annotation processing: java.lang.NoClassDefFoundError: com/mongodb/DBObject|#]
[#|2010-03-24T11:42:15.259+0100|SEVERE|glassfishv3.0|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=28;_ThreadName=Thread-1;|Exception while loading the app
org.glassfish.deployment.common.DeploymentException: java.lang.NoClassDefFoundError: com/mongodb/DBObject
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:171)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:125)
at org.glassfish.internal.data.ApplicationInfo.load(ApplicationInfo.java:224)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:338)
I tried adding it to the NetBeans project (Properties -> Libraries -> Compile -> Add Jar, enable 'Package'), and I also tried manually copying the jar file to $GF_HOME/glassfish/domains/domain1/lib (where the mysql-connector already resides).
Do I need to 'register' the library with the container? Reference it via Annotation? Extend the classpath of the container to include the library?
Hmm... Shouldn't you put this "driver" in glassfishv3/glassfish/domains/domain1/lib/ext?
You could put shared libs to lib/ext of your domain. commons-logging and jdbc drivers are often added in this domain path.
Common Class Loader
GlassFish v2 has a well defined Class
Loader hierarchy which identifies the
common class loader as the proper way
to deal with shared libraries. So to
make a long story short, putting you
libraries and other framework JARs in
domains/domain1/lib is all you need to
do.
lib/, not lib/ext
The person asking me the question had
tried putting the libraries in
domains/domain1/lib/ext which
triggered an interesting
ClassNotFoundError for core Java EE
classes such as
javax.servlet.http.HttpServlet. Shing
Wai Chan was quick to explain that
domains/domain1/lib/ext is part of
-Djava.ext.dirs which makes any of its JARs be considered as a JDK extension
which means web app frameworks placed
there will be loaded before
webcontainer implementation classes as
they are higher up in the classloader
delegation chain.
Glassfish has own Class loader hierarchy, http://docs.oracle.com/cd/E19798-01/821-1752/beade/index.html
I face the same problem in my project and then I put all my Third party libraries in domain/domain1/lib and my problem solved. On other way round, my problem was solved too by putting libraries in glassfish/lib.
In my case I was using Oracle Express Edition 11gR2 and Glassfish 3.1.2 and the ONLY way that works in my case was putting the ojdbc6 in:
C:\Program Files\glassfish-3.1.2.2\glassfish\lib
Go to your Glassfish doamin directory.
Then go to lib folder.
Place the libraries there.
Restart the glassfish and run.
(Ex) C:\glassfish3\glassfish\domains\domain1\lib
Try to put Your libs into $GF_HOME/glassfish/modules/.
It's dirty, but will work.