Simple ejb client app (servlet) using JNDI architecture. - eclipse

I'm tryng to build a simple "Hello World" app using EJB's and Servlet. I'm strongly confused about how it should look like. I have two projects in eclipse. One contains EJB Stateless session bean and its interface (both of them in this same package) the other one contains bean, interface and servlet which should be able to call both beans methods. I've added the remote project (from the other project) to "Projects" in build path. Now i've imported the remote interfaces to the servlet. Now the servlet looks like this:
import pl.test.IHelloRemote;
import pl.other.IDateRemote;
#WebServlet("/TestServlet")
public class Control extends HttpServlet {
private static final long serialVersionUID = 1L;
private InitialContext ic;
private IHelloRemote iHelloRemote;
private IDateRemote iDateRemote;
public Control() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
ic = new InitialContext();
iHelloRemote = ic.lookup ("java:global/test-project/HelloBean!pl.test.iHelloRemote");
iDateRemote = ic.lookup ("java:global/other-project/DateBean!pl.other.iDateRemote");
} catch (NamingException ex) {
ex.printStackTrace();
}
iHelloRemote.sayHello();
iDateRemote.getDate();
}
}
As I mention the "other-project" is included in the build path. Here's how the single bean that I want to use looks like:
package pl.other;
import javax.ejb.Stateless;
#Stateless
public class DateBean implements IDateRemote {
public DateBean() {}
#Override
public void getDate {
//some code here
}
}
Now my questions.
Why (and how to fix that) during deployment i get error:
Class [ Lpl/other/IDateRemote; ] not found. Error while loading [ class TestServlet]
Can EJB beans be located in default package? Why Elipse does'nt allows that?
Where shall bean interfaces be located? In the same package as bean? In the Servlet package? What is the "best practice" setup of the files in this kind of project?
As for now the setup is like follows:
test-project
|- (default package)
|- TestServlet
|- pl.test
|- IHelloRemote
|- HelloBean
other-project
|- pl.other
|- IDateRemote
|- DateBean
Thank You for replies and patience.
Smok.

Related

EJB not initializing in Wildfly 9.0.0 using #EJB

I'm trying to migrate from EJB2.x to EJB3.x and i'm using Wildfly 9.0.0.
The old EJB2.x is working in JBoss 4.2.2 and this is how it looks like:
public interface WUFFacadeRemote extends EJBObject {
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
public interface WUFFacadeHome extends EJBHome {
public WUFFacadeRemote create();
}
public class WUFFacade {
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
}
public class WUFAction extends HttpServlet implements IAction {
public void doPost(HttpServletRequest request, HttpServletResponse response) {
...
Object objRef = ic.lookup("java:comp/env/wUF");
com.wuf.WUFFacadeHome home = (com.wuf.WUFFacadeHome) PortableRemoteObject.narrow(objRef, com.wuf.WUFFacadeHome.class);
engine = home.create();
//engine gets the reference, and I can use it normally.
...
}
}
I also have the ejb-jar.xml and it's working. Now, the solution I was thinking to EJB3.x and Wildfly 9.0.0 is as below:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet implements IAction {
#EJB
private WUFFacadeRemote engine;
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Here I should be able to use my engine.
//Wildfly starts and I call the page, engine is not null at this moment,
//but after I call the page again, it becomes null and remains null.
}
}
#Stateless
#Remote(WUFFacadeRemote.class)
public class WUFFacade extends RootFacade implements WUFFacadeRemote, Serializable {
public WUFFacade() { }
#EJB
FUFHome home;
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
private Col load(ClientData data,InitialContext ic) {
//here i'm calling home.
// but home is always null. It was supposed to have the #EJB reference initialized.
//But instead I get a null pointer...
home.findByFilter(loader);
}
}
#Remote(FUFHome.class)
public interface FUFHome {
FUF create(FUFValue fUFValue);
FUF findByPrimaryKey(FUFPK pk);
Collection findByFilter(FacadeLoader loader);
}
public interface WUFFacadeRemote{
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
I don't have ejb-jar.xml anymore, the deploy is sucessfully done and Wildfly starts with no errors. Then the first time I call the page in question, it seems that #EJB is working (Debug is "Proxy for remote EJB StatelessEJBLocator for "bus-facade/WUFFacade", view is interface com.wuf.WUFFacadeRemote, affinity is None"), the value is not null, but for all subsequent calls, my variable is null and I got a NullPointerException.
I really don't know what i'm doing wrong (maybe i'm completely lost), but to me, #EJB should be working correctly like that. What am I missing? Thanks.
As i'm using EJB3.x i'm just using annotations now, (this seems to be ok).
JNDIs:
JNDI bindings for session bean named FUF in deployment
java:global/fumo/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:app/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:module/FUF!apyon.components.fumo.fuf.FUF
java:global/fumo/bus-entities-fumo/FUF
java:app/bus-entities-fumo/FUF
java:module/FUF
JNDI bindings for session bean named WUFFacade
java:global/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:app/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:module/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:jboss/exported/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:global/fumo/bus-facade-fumo/WUFFacade
java:app/bus-facade-fumo/WUFFacade
java:module/WUFFacade
I think I found a possible solution to the problem. I'll still try to find another one, but this is good so far.
After changing to a .war and keeping my other projects in .ears it's working. Maybe the problem was because I have a RootController servlet im my main.ear, which is the starting point of the aplication. The context starts there and then it redirects to fumo.ear (now fumo.war).
For some reason, I always was getting a null in my EJB after entering a page. It was always hapening when I first entered a JSP and tried to call the page again. My solution to this is:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet {
private WUFFacadeRemote engine;
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
doPost(req, resp);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
if(engine == null) {
InitialContext ic;
try {
ic = new InitialContext();
engine = (WUFFacadeRemote) ic.lookup("java:global/fumo/WUFFacade!fumo.wuf.WUFFacadeRemote");
} catch (NamingException e) {
e.printStackTrace();
}
}
//here I always have the context now.
}
}
And as a .war my structure now looks like this:
So other annotations like #Inject and #EJB are now working. Always when i'm being redirect from a JSP calling a Servlet or some action, I first check if the context is not null, otherwise I lookup it. My #Stateless are working and the #PersistenceContext and #Remote are working too.
#Stateless
public class WUFFacade implements WUFFacadeRemote {
#Inject
private FUFRules rules;
#EJB
private FUFHome home;
private Col load(ClientData data, InitialContext ic) throws InterfaceException {
try {
// home here is nor null anymore.
Collection res = (Collection) home.findByFilter(loader);
...
} catch (InterfaceException e) {
e.printStackTrace();
}
...
return data;
}
}
So I'd like to thank everyone who helped in the thread. It was a good way to understand and see the problem or to find a workaround. As I said, I'll still try the .ear in the future, but as a simplified packaging it definitely works.

Java EE Servlet and REST path clashing

I am trying to write a Java web application that provides both HTML and REST interface. I would like to create a servlet that would provide the HTML interface using JSP, but data should also be accessible via REST.
What I already have is something like this for the REST:
#javax.ws.rs.Path("/api/")
public class RestAPI {
... // Some methods
}
and
#WebServlet("/servlet")
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Howdy at ");
}
}
Now, when I change the #WebServlet("/servlet") annotation to #WebServlet("/"), the servlet stops working probably due to path clash with the REST.
How can I provide REST on specific path and HTML in the root?
Thank you,
Lukas Jendele
This seems to work OK for me. What I did:
In my pom.xml, I have a dependency on org.wildfly.swarm:undertow (for Servlet API) and org.wildfly.swarm:jaxrs (for JAX-RS). And of course the Swarm Maven plugin.
For servlet, I have just this one class:
#WebServlet("/")
public class HelloServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello from servlet");
}
}
For JAX-RS, I have these 2 classes:
#ApplicationPath("/api")
public class RestApplication extends Application {
}
#Path("/")
public class HelloResource {
#GET
public Response get() {
return Response.ok().entity("Hello from API").build();
}
}
To test, I run curl http://localhost:8080/ and curl http://localhost:8080/api. Results are as expected. (Maybe my example is too simple?)

Injecting EJB into Rest Exception Handler

I'm trying to inject a local #Stateless EJB into a Rest exception handler but getting the following error.
javax.naming.NameNotFoundException: Name [Test] is not bound in this Context. Unable to find [Test].
The maven Web project is running on Apache-tomee-1.7.1-jaxrs.
The EJB:
#Stateless(name = "Test")
public class Test {
public void sayHello() {
System.out.println("Hello");
}
}
The Exception handler which from my understanding I must treat as a client to the EJB.
#Provider
public class TestExceptionHandler implements ExceptionMapper<Throwable> {
#Context
HttpServletRequest request;
#Override
public Response toResponse(Throwable throwable) {
InitialContext context;
try {
context = new InitialContext();
Test test = (Test) context.lookup("Test");
test.sayHello();
} catch (NamingException ex) {
ex.printStackTrace();
}
return Response.ok().build();
}
}
I have also tried to do the following for the lookup: context.lookup("java:comp/env/Test");
The http://openejb.apache.org/jndi-names.html documentation is very difficult to understand.
Also tried the following which was my first attempt. http://blog.iadvise.eu/2015/06/01/jee-using-ejb-and-context-annotations-in-a-jax-rs-provider-class/
Am I missing any configuration in the tomee server or in my code?
The java:comp/env namespace is for the EJB references, not EJBs. You have not declared an EJB reference anywhere.
It's probably easiest to directly look up the EJB using lookup("java:module/Test") (assuming the EJB is packaged in the war, otherwise, java:app/ejbmodname/Test) because JAX-RS does not support EE injection by default. To declare an EJB reference, you would need to make the provider class an EJB itself or a CDI class (add beans.xml to the module), and then declare a field as #EJB(name="Test") Test myBean;.

Jersey EJB injection

I read a lot about the possibility of injection with jax rs 2.0 and in particular with jersey.
I even read that ejb injection is expected in jax rs 2.0 spec. But i still haven't found a unique solution among the variety of posts i read over the net.
In my use case i'm working with:
WildFly 9.0 and Jersey 2.x
I have a webapplication exposing my REST services and importing a jar implementing my model data.
This is the CDI approach:
#RequestScoped
#Path("/myPath")
public class ModelRetriever {
#Context
SecurityContext securityContext;
#Inject
private IMyModel MyModel;
#Path("{i}")
#GET
#Produces("application/json")
public Response countries(#PathParam("i") String countryId)
throws JSONException, Failure, IOException {
MyModel.doSomething();
}
This is my IMyModel interface
public interface IKasPrincipal extends Principal {
public void doSomething();
}
And this is MyModel implementation:
#RequestScope
public class MyModelImpl implements IMyModel {
public void doSomehting() {
doSomething();
}
}
Another method i tried is to use EJB injection changing my previous annotations like this:
#Stateless
#Path("/myPath")
public class ModelRetriever {
#EJB
private IMyModel MyModel;
#Path("{i}")
#GET
#Produces("application/json")
public Response countries(#PathParam("i") String countryId)
throws JSONException, Failure, IOException {
MyModel.doSomething();
}
This is my IMyModel interface
#Local
public interface IKasPrincipal extends Principal {
public void doSomething();
}
And this is MyModel implementation:
#Stateless
public class MyModelImpl implements IMyModel {
public void doSomehting() {
doSomething();
}
}
i get a null object using EJB approach and i get this exception using CDI
Caused by: org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=IMyModel,parent=ModelRetriever,qualifiers={},position=-1,optional=false,self=false,unqualified=null,616459318)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:75)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:211)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:234)
So is there anything i'm missing?
see other Stack Overflow related posts:
Dependency injection with Jersey 2.0
HK2 Jersey EJB 3 injection
The problem you are having is that HK2 does not know about anything that was not registered directly into it, and HK2 tries to to satisfy all dependency in your Jersey aware class.
I has this issue a while back. Then I discovered that Jersey uses HK2 internally. HK2 is a JSR-330 implementation (CDI).
One would think that a open-source project would declares it's CDI beans and use them regardless of the CDI implementation, but it looks like its not that way.
see : https://java.net/jira/browse/JERSEY-1933
see : https://hk2.java.net/integration.html
You can register your components into HK2...
see : https://jersey.java.net/documentation/latest/ioc.html
For all I know, you cannot inject CDI components (or anything else, as EJB) into Jersey's classes using your own (or your container's) CDI implementation, unless you use Glassfish (which personally I would never use) which in turn uses HK2 as its CDI implementation.
To me, this is a major draw back. But the only(?) draw back of Jersey.
-Maybe I missed something (which is very possible)
-Maybe this is a trick from Oracle so that you can't use Jersey in, let's say, your Websphere app which uses OpenWeb Beans as CDI implementation.
-Maybe they hardwired it to HK2, and just don't care that Jersey can't be used as a drop in component in your application, which relies on CDI or EJB
I'm not aware of why #EJB not worked, but, you can use #Produces/#Disposes bean.
#ApplicationScoped // or some other scoped
public class MyModelProducer {
#Produces public MyModel produceMyModel() {
}
public void disposeMyModel#Disposes final MyModel model) {
}
}

GlassFish exception

Im quite new to all this stuff. I try to launch a webservice via GlassFish. When i try to build this project i get an error.
ant -f /home/philipp/NetBeansProjects/sks3 -DforceRedeploy=false -Ddirectory.deployment.supported=true -Dnb.wait.for.caches=true run
init:
deps-module-jar:
deps-ear-jar:
deps-jar:
check-rest-config-props:
generate-rest-config:
library-inclusion-in-archive:
library-inclusion-in-manifest:
compile:
compile-jsps:
In-place deployment at /home/philipp/NetBeansProjects/sks3/build/web
Initializing...
deploy?DEFAULT=/home/philipp/NetBeansProjects/sks3/build/web&name=sks3&contextroot=/sks3&force=true failed on GlassFish Server 3.1.2
Error occurred during deployment: Exception while deploying the app [sks3] : Invalid TYPE-level #EJB with name() = [] and beanInterface = [class java.lang.Object] in class Webservice.MeasurementResources. Each TYPE-level #EJB must specify both name() and beanInterface().at org.glassfish.apf.AnnotationInfo#3b63118a. Please see server.log for more details.
/home/philipp/NetBeansProjects/sks3/nbproject/build-impl.xml:1028: The module has not been deployed.
See the server log for details.
BUILD FAILED (total time: 6 seconds)
I dont have a clue what is going wrong but according to the message it has to be in the file MeasurementResurces.java ...
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package Webservice;
import Exception.DALException;
import dal.MeasurementDao;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.Path;
import repo.Measurement;
/**
*
* #author philipp
*/
//#Stateless
//#inject
#EJB
//#LocalBean
#Named
#Path("Measurement")
public class MeasurementResources {
#Inject
MeasurementDao mDao;
public void add(Measurement arg) throws DALException{
mDao.save(arg);
}
/* public void getAll(Measurement arg) throws DALException{
mDao.getAll();
}
*/
}
Someone has at least a hint whats the problem?
You are using a Type-Level EJB without declaring name and beanInterface.
/**
*
* #author philipp
*/
//#Stateless
//#inject
#EJB(name="MyEjb", beanInterface=RemoteEjb.class)
//#LocalBean
#Named
#Path("Measurement")
public class MeasurementResources {
#Inject
MeasurementDao mDao;
public void add(Measurement arg) throws DALException{
mDao.save(arg);
}
}
#Remote
public interface RemoteEjb {
public void doSomething();
}
#Stateless
public class MyEjb implements RemoteEjb {
...
}
name is the name of the EJB you trying to inject. beanInterface is the Local or Remote interface. It's not a real injection. It is a way to use annotation as a replacement of deployment descriptor ejb-ref element. You should use a JNDI lookup in order to inject the ejb.
I don't know what are you trying to do but the common way to inject an ejb is the following:
#Named
#Path("Measurement")
public class MeasurementResources {
#EJB
private MyEjb myejb;
#Inject
MeasurementDao mDao;
public void add(Measurement arg) throws DALException{
mDao.save(arg);
}
...
}