Is it possible to have EJBs in domain1/lib using GlassFish? - java

I use GlassFish 4 web profile and I have the following interface and class.
#Local
public interface SomeService {
...
}
#Singleton
public class SomeServiceBean implements SomeService {
...
}
When I put interface and class in .war archive (that is in domain1/autodeplay) everything works fine. However, when I put interface and class in separate .jar archive (that is in domain1/lib) then deploying war application I get:
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=com.temp.MyServlet/someService,Local 3.x interface =com.temp.SomeService,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
at com.sun.enterprise.deployment.util.ComponentValidator.accept(ComponentValidator.java:374) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.DefaultDOLVisitor.accept(DefaultDOLVisitor.java:78) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.ComponentValidator.accept(ComponentValidator.java:123) ~[dol.jar:na]
at com.sun.enterprise.deployment.util.ApplicationValidator.accept(ApplicationValidator.java:152) ~[dol.jar:n
...
I don't use any xml descriptors. So, is it possible to have EJBs in domain1/lib and if yes, how to make EJB container find them? P.S. I tried in GF 4 full - result is the same.

EJBs cannot be added as a library to GlassFish, libraries are just added to the classpath and any annotations on them are ignored and they do not go through the EJB container. If you do want your EJBs as a seperate JAR, they can be deployed just like a WAR or EAR file.
In the Glassfish reference manual for the add-library command it says that it "adds the library to the class loader directory", while for the deploy command it says that "Applications can be...EJB modules".
Also by looking at the source code for Glassfish it can be worked out that all libraries are simply added to the Classloader either at launch (See here and here) or if in applibs then when the application is deployed (See here).

Related

Is there a way to package an EJB module with a WAR without an EAR?

I currently have the following project structure
EAR
|---myapp1.war
|---myapp2.war
|---myapp-ejb.jar
I would like to get rid of the ear and deploy myapp1 and myapp2 on their own. I tried to make myapp-ejb.jar a maven dependency of the two war and everything works fine at compile time. Nevertheless, there are a lot of jndi lookups in the code that fail at deploy time. Is there a way to make this to work?
Theoretically, it is possible to have ejb in a web archive (war).
Although not necessary, you could try to put a 'ejb-jar.xml' file (located in the WAR module’s WEB-INF) to replace the normal auto-discovery mechanism ?
Be also aware that the WAR file must be version 2.5 or later to contain EJB content.
Extract the WAR from the EAR
Scope ejbs as "provided" per https://stackoverflow.com/a/42847318/8528208
Place the ejb.jar in your WAR's WEB-INF/lib per https://stackoverflow.com/a/6968674/8528208
Further documentation at https://www.ibm.com/docs/en/was/8.5.5?topic=modules-ejb-content-in-war
--
Archived edits comments refer to:
Update-
Is the ejb.jar in the build class path of your .war? If your project is maven based, is the ejb.jar a dependency of the .war project? If so, try adding the EJB module as a "provided" dependency per https://stackoverflow.com/a/42847318/8528208
--
"An .ear file is a collection of entities (i.e., .war files), so you can simply extract the .war file from the .ear file and deploy it."
-per https://stackoverflow.com/a/26658071
If this doesn't help, can you add a lookup attribute in your #EJB annotations such as
#EJB(lookup="java:global/mwf_ejb/UserManager")
Similar to this answer?
https://stackoverflow.com/a/10156279/8528208
I'm writing an answer to my own question, since I solved the issue. It is perfectly fine to use EJBs with a WAR only (no EAR) as stated here https://docs.oracle.com/cd/E19798-01/821-1841/gippi/index.html.
As for the lookups calls, the correct way to do it is described here https://docs.oracle.com/cd/E19798-01/821-1841/girgn/index.html.
The issue I was facing wasn't really related to the lookups, as I was thinking, but it was due to the way most of the EJBs were initialized.
I noticed that in most of the classes there was some nasty initialization code like the following:
#Stateless
public class FooResource
{
FooEjb fooEjb = lookupFooEjb();
private FooEjb lookupFooEjb()
{
javax.naming.Context c = new InitialContext();
return (FooEjb) c.lookup("java:global/FooApplication/FooModule/FooEJB!FooInterface");
}
}
This works fine with the EAR because the EJB module is loaded before the WAR archives, so the lookups do not fail.
My guess is that when you package the EJBs with the WAR, it loads the EJBs as they are needed, computing the dependencies based on the #EJB annotation, so that kind of initialization fails since the EJB might be not loaded yet. To make it work, I just removed the lookup and added the annotation #EJB.
#Stateless
public class FooResource
{
#EJB
FooEjb fooEjb;
}

JDBC driver not found (servlet, DAO, mariaDB) [duplicate]

I developer a web application using Java. When I deploy it to my application server (Jetty, Tomcat, JBoss, GlassFish, etc.) throws an error. I can see this error message in the stacktrace:
java.lang.ClassNotFoundException
Or
java.lang.NoClassDefFoundError
What does this mean and how can I fix it?
What does this mean?
First, let's see the meaning of java.lang.ClassNotFoundException:
Thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader.
The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
Usually, this happens when trying to open a connection manually in this form:
String jdbcDriver = "...'; //name of your driver
Class.forName(jdbcDriver);
Or when you refer to a class that belongs to an external library and strangely this class cannot be loaded when the application server tries to deploy the application.
Let's see the meaning of java.lang.NoClassDefFoundError (emphasis mine):
Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
The last part says it all: the class existed at compile time i.e. when I compiled the application through my IDE, but it is not available at runtime i.e. when the application is deployed.
how can I fix it?
In Java web applications, all third party libraries used by your application must go in WEB-INF/lib folder. Make sure that all the necessary libraries (jars) are placed there. You can check this easily:
- <webapp folder>
- WEB-INF
- lib
+ jar1
+ jar2
+ ...
- META-INF
- <rest of your folders>
This problem usually arises for JDBC connectivity jars (MySQL, Derby, MSSQL, Oracle, etc.) or web MVC frameworks libraries like JSF or Spring MVC.
Take into account that some third party libraries rely on other third party libraries, so you have to add all of them in WEB-INF/lib in order to make the application work. A good example of this is RichFaces 4 libraries, where you have to download and add the external libraries manually.
Note for Maven users: you should not experience these problems unless you have set the libraries as provided, test or system. If set to provided, you're responsible to add the libraries somewhere in the classpath. You can find more info about the dependency scopes here: Introduction to the Dependency Mechanism
In case the library must be shared among several applications that will be deployed on your application server e.g. MySQL connector for two applications, there's another alternative. Instead of deploying two war files each with their own MySQL connector library, place this library in the common library folder of the server application, this will enable the library to be in the classpath of all the deployed applications.
This folder vary from application server.
Tomcat 7/8: <tomcat_home>/lib
JBoss 7/Wildfly: <jboss_home>/standalone/lib
The class must exist under WEB-INF/classes or be inside a .jar file under WEB-INF/lib. Make sure it does.
Same problem happen with me.
Might be possible one of your libraries are using some classes internal which is not available
in your lib or maven dependency pom.xml.
Thats means you have analyze your error logs and identify these classes and then import all dependencies in maven or lib folder.
I have fixed this error by the same way.
because some of my libraries are using activation.jar and json.jar internally.

JAX-RS - Loading #Provider classes from a jar file

I have a simple Rest application that is deployed to an IBM MobileFirst 7.1 Liberty Server. (I don't know the implementation of the JAX-RS but it is included with the liberty server runtime I believe)
I have to share some of my common code with other teams, so I moved some of the code into a separate maven project to be jared and added as a server library. This all works great until I had to add some #Provider annotated classes into the separate maven project. Specifically, some ExceptionMapper implementations marked with the #Provider annotation.
I have tried setting the class directly within the Application classes getClasses() method. This seemed to work, but I get a warning message saying that my exception mapper implementations need to be marked with the #Provider or #Path annotations (which they are).
Is there some sort of trick to get JAX-RS to recognize these resource classes from a Jar file?
In order to have the #Provider recognized, please try to put the JAR inside the adapter /lib folder instead of the server/lib folder.

netbeans 7-8, inject of remote ejb

Hi, I have an EJB project called "service-ejb" with this:
#Stateless
#Remote(ServiceRemote.class)
public class Services implements ServiceLocal, ServiceRemote {
[...business code...]
}
the I have the local interface, in the same project:
#Local
public interface ServiceLocal { }
and the remote interface, in a class library project called "service-lib":
#Remote
public interface ServiceRemote {
public boolean checkIfOk();
}
I can deploy it without problem, alone or in a java EE application. The point is that I don't understand how to tell NetBeans that I wish to call that beans from another application. For example I have another java EE project with a war component, where inside a servlet I wrote:
#EJB
private ServiceRemote serviceTest;
but of course it will fail compiling, so I tried with:
InitialContext ic = new InitialContext();
ServiceRemote serviceTest = (ServiceRemote) ic.lookup("ServiceRemote");
with no luck... Where in NetBeans I can tell it to use the "service-lib" as a reference? I don't want it to be added as library and then deployed with the ear, I only want NetBeans to compile correctly the code.
Sorry if the question sound silly, but I've read the documentation and I don't understant what I'm missing...
--- edit ---
I'll try to be more clear. "service-ejb" reference "service-lib", so I've deployed "service-ejb" to glassfish. Correctly, I have:
glassfish_applications_directory $ find -name "service*"
./__internal/service-ejb
./__internal/service-ejb/service-ejb.jar
./service-ejb
./service-ejb/com/tecytal/components/email/beans/Service.class
./service-ejb/com/tecytal/components/email/interfaces/local/ServiceLocal.class
./service-ejb/service-lib.jar
Then I open a java EE project, let's call it "myEngine" with a war module "myEngine-war". I've tried to add to "myEngine-war" a reference to "service-lib", of course, and in this case it compile well. The point is that I can do everything, tell to netbeans NOT to package the "service-lib" with the war, but when I deploy "myEngine" I get:
glassfish_applications_directory $ find -name "service*"
./myEngine/lib/service-lib.jar
./__internal/service-ejb
./__internal/service-ejb/service-ejb.jar
./service-ejb
./service-ejb/com/tecytal/components/email/beans/Service.class
./service-ejb/com/tecytal/components/email/interfaces/local/ServiceLocal.class
./service-ejb/service-lib.jar
I DON'T want to have TWO service-lib.jar in my server, one in the service-ejb and one in myEngine, I don't understand how I can use a remote ebj in netbeans telling to him NOT TO deploy the same lib 3214899213 times :)
I recommend to add the remote service interface and all classes it references (including exceptions) in a separate jar. Then in the other 2 projects declare a dependcy to this jar.
I don't want it to be added as library and then deployed with the ear
I recommed to add only the service-lib contain the interface etc as a library and deploy it with the ear, not the whole service-ejb containing the implementation.

Deploying 2 war files with common classes in JBoss

I have two war file app1.war and app2.war deployed in a single JBoss instance. Package names for java classes for both war files starts with com.myapp
To add further, there are some Classes that are common between the two apps while there are some that have same fully qualified class names but are different (Source Code has changed).
I want to know, if this could pose threat of any kind to the deployment scenario?
You could get class loading problems if your applications are not isolated, i.e. have their own class loading repository and class loaders. If you configure JBoss to isolate the applications from each other you should be fine (I don't know what is the default for your version but 4.2.3 that we use does not isolate apps by default).
To clarify that a bit:
If you have two classes with different implementations but the same FQCN you could get the wrong class from the class loader for the application that is loaded second. Even if the implementation was the same you could get class cast exceptions or other strange behavior if one app gets the class from the other app.
I had a similar situation with multiple apps.Look at my solution here
Best way is to isolate class loading for your application archives.
For JBoss 5.1.0 GA following worked for me.
Create jboss-classloading.xml file in WEB-INF folder.
Added following lines to this file
Here,
export-all="NON_EMPTY" => Makes sure the classes loaded for this app is not exported
import-all="true" => Imports and uses all of the class definition available.
parent-first="false" => If more than one class with same name is found, one defined under the application will be used first.
FYI. This also helped me embedding the log configuration of log4j in the application war file. Will need to place log4j.xml in WEB-INF/classes and have a log4j.jar in WEB-INF/lib folder.
There will be one class loader instance for each application or standalone module. In other words, classes in app1.war will be loaded in different class loader than the classes in app2.war. This is the default behavior of any Java EE server; So it really doesn't matter about having classes with the same package/names and/or different content. This is the default behavior of any Java EE server.
Having said that, if you tweak the class loader policy of the server or try to load classes (reflect) using anything other than Thread.currentThread().getContextClassLoader(), you could be asking for trouble.

Categories