there is an issue that troubles me and I cannot find any uniform way to solve it around the internet. I am developing an enterprise application using Java EE, Glassfish and Netbeans.
I have two instances of Glassfish set up, and I am building an enterprise application split among the two. I have a web page (with a couple of JSPs and a couple of HttpServlets) running on one instance of Glassfish. On the other instance, I want to implement the business logic of the app. That is, I have some Java Entity Beans in it, and also an EJB with a remote interface that uses these entity beans.
My goal is to be able to access the EJB remotely from the servlets on the first instance of glassfish. I have followed the instructions found in this post but unsuccessfully. I am providing code snippets to get more specific...
On one instance of Glassfish, EJB's remote Interface:
@Remote
public interface MyEjbRemote {
//...
}
and the stateless bean:
@Stateless(name="ejb/MyEjb")
开发者_开发知识库public class MyEjb implements MyEjbRemote {
//...
}
On the other instance:
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyEjbRemote = lookupEjb();
//...
}
private MyEjbRemote lookupEjb() {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
//default: localhost
props.setProperty("org.omg.CORBA.ORBInitialHost",
"localhost");
//default: 3700
props.setProperty("org.omg.CORBA.ORBInitialPort", "2037");
InitialContext ic = new InitialContext(props);
return (MyEjbRemote) ic.lookup("ejb/MyEjb");
}
}
Unfortunately when I launch my website and try to lookup the remote ejb I get the following exception:
WARNING: Internal error flushing the buffer in release()
WARNING: StandardWrapperValve[jsp]: PWC1406: Servlet.service() for servlet jsp threw exception
java.io.IOException: Stream closed
at org.apache.jasper.runtime.JspWriterImpl.ensureOpen(JspWriterImpl.java:277)
at org.apache.jasper.runtime.JspWriterImpl.clearBuffer(JspWriterImpl.java:222)
at org.apache.jsp.home_jsp._jspService(home_jsp.java from :76)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:109)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:406)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:483)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:373)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:662)
What is missing from my implementation?Any suggestions/ideas? Please ask if something is missing from the description of my problem, it's my first time posting in this site. I appreciate your time!
Ilias
I see a few wrongs here.
The most practical is probably that the exception is from a JSP page and seemingly has nothing to do with the Servlet nor the EJB access. Both of these do not appear in the stack trace. You probably have a JSP called home.jsp. It's trying to write to the response, but the stream that represents it has already been closed. Somewhere you're doing something nasty, but it's very probably unrelated to EJB.
A more theoretical wrong is that your design looks like a big anti-pattern. Using remote EJB calls for the sole sake of "separating business logic" is an EXTREMELY bad idea. If you want to separate your business logic, just put your EJBs in an EJB module, your Servlets and JSPs in a WEB (war) module and bundle the two together in an EAR. Use local interfaces. Creating a project supporting this is typically only a few clicks in IDEs like Netbeans or Eclipse, and the performance and sanity of your design is much, much better.
Note that remote EJBs most definitely have their use, but they should be used very sparingly. Use them to control coarse grained jobs or so on a remote server, where the particular instance of that server has a specific meaning. E.g. you might have a single gateway server in your cluster where messages (via JMS) are queued and processed in batch to be send to the external network. Use remote EJBs here to administrate that remote server.
From your problem description I taste that you want to use this second Glassfish instance for 'regular' fine-grained business logic. Unless you are 100% certain about what you are doing and you are 100% certain that your specific problem absolutely requires remote communication, I strongly advice you to drop this idea.
Complete Glassfish 3.1 + Eclipse Helios + EJB 3.1 Example
Simple Main.java (SIMPLE Client Project NO NEED TO DEPLOY)
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
// optional. Defaults to localhost. Only needed if web server is running
// on a different host than the appserver
props.setProperty("org.omg.CORBA.ORBInitialHost", "127.0.0.1");
// optional. Defaults to 3700. Only needed if target orb port is not 3700.
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
InitialContext ic = new InitialContext(props);
GlassfishSessionBeanRemote gRemote = (GlassfishSessionBeanRemote)ic.lookup("java:global/EJBGFish/GlassfishSessionBean!com.example.GlassfishSessionBeanRemote");
gRemote.sayHello();
EJB Module - YOU MUST DEPLOY ALL THE BELOW THREE AS A JAR FILE (Simply Run as Server in Eclipse) - DEPLOYED
@Stateless
public class GlassfishSessionBean implements GlassfishSessionBeanRemote, GlassfishSessionBeanLocal {
@Override
public void sayHello() {
System.out.println("First Glassfish App!");
}
REMOTE AND LOCAL INTERFACES ARE AS BELOW.
@Remote
public interface GlassfishSessionBeanRemote {
public void sayHello();
}
@Local
public interface GlassfishSessionBeanLocal {
public void sayHello();
}
MOST IMPORTANT THINGS TO BE DONE:
- MUST ADD gf-client.jar from GLASSFISH 3.1 LIB FOLDER to Main. java's class path.(The first one)
- ADD EJB PROJECT to Main.java's class path.
I thinks you need to deploy EJB project; After that, insert code like this to client project:
try {
Context c = new InitialContext();
HelloRemote z = (HelloRemote) c.lookup("java:global/Pro_EJBModule1/Hello!newpackage.HelloRemote");
System.out.println(z.sayHello("NGA"));
} catch (NamingException ne) {
System.out.println(ne);
throw new RuntimeException(ne);
}
Pro_EJBModule1 is the EJB project's name.
A relevant answer which accounts for a stand alone client rather than a deployed one can be found in this answer as well.
精彩评论