Showing posts with label EJB. Show all posts
Showing posts with label EJB. Show all posts

Thursday, December 31, 2015

JAXWS and EJB can live together

If the SEI code were accessible from the client within the same package, do I still need the following code in order to access the service code?
   URL url = new URL("http://localhost:8080/ws1?wsdl");
   QName qname = new QName("http://webmethod.huahsin.org/", "HelloWorldImplService");
   HelloWorldImplService service = new HelloWorldImplService(url, qname);
   IHelloWorld manager = service.getHelloWorldImplPort();
   System.out.println(manager.sayHelloWorld());
Imaging I have the following SEI code and there are sit in the same application:
package org.huahsin.webmethod;
 
…
 
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…
 
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
I just feel a bit weird in doing this since both client code and server code are live in the same application. I did a search on the forum and got to know that web service code can be accessed through EJB. Just "top up" the @Stateless and @Remote to the SEI and we are done.
@Remote
@WebService
@SOAPBinding(style=Style.DOCUMENT)
public interface IHelloWorld {
 
 @WebMethod
 String sayHelloWorld();
}
 
 
package org.huahsin.webmethod;
 
…

@Stateless
@WebService(endpointInterface="org.huahsin.webmethod.IHelloWorld")
public class HelloWorldImpl implements IHelloWorld {
 
 @Override
 public String sayHelloWorld() {
  return "Hello World";
 }
 
}
To access the web service code in EJB way, do the following (excuse myself, I'm doing it in JSF bean):
@ManagedBean
@RequestScoped
public class HelloWorldController {

 @EJB
 private IHelloWorld helloWorld;
 ...
 ...
Sound cool? The best part of this is no more generating stub code.

Thursday, December 17, 2015

Wrong component? EJB can't used as web component?

Shit!! Something was wrong! When I deploy my web app into JBoss, it throws me this error:
(MSC service thread 1-2) MSC000001: Failed to start service jboss.deployment.unit."ejbWeb1.war".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."ejbWeb1.war".PARSE: JBAS018733: Failed to process phase PARSE of deployment "ejbWeb1.war"
 at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:127) [jboss-as-server-7.3.4.Final-redhat-1.jar:7.3.4.Final-redhat-1]
 at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.4.GA-redhat-1.jar:1.0.4.GA-redhat-1]
 at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.4.GA-redhat-1.jar:1.0.4.GA-redhat-1]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_79]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_79]
 at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]
Caused by: java.lang.RuntimeException: JBAS018043: org.huahsin.ejb.Authentication has the wrong component type, it cannot be used as a web component
 at org.jboss.as.web.deployment.component.WebComponentProcessor.deploy(WebComponentProcessor.java:120)
 at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:120) [jboss-as-server-7.3.4.Final-redhat-1.jar:7.3.4.Final-redhat-1]
 ... 5 more
The clue is org.huahsin.ejb.Authentication can not be used as web component. Ok! Fine. What is the root cause of this? I'm gonna find out this...

I got an EJB code as stated below:
package org.huahsin;

@Remote
public interface AuthenticationRemote {
    public int status();
}

package org.huahsin;

@Stateless(name="authenticate")
@LocalBean
public class Authentication implements AuthenticationRemote {
    @Override
    public int status() {
        return 1234;
    }
}
This code was located in a standalone EJB project. And then I have another set of code which will accessing the EJB code:
package org.huahsin;

@WebServlet("/authentication")
public class Authentication extends HttpServlet {

 @EJB
 private AuthenticationRemote authenticationRemote;

 public Authentication() {
  super();
 }

 @Override
 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
  int result = authenticationRemote.status();
  ...
  ...
 }
 
 @Override
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
  
 }
}
Yet, this is another web app project. So, to make these two projects work together, I did the following configuration on the web project:
  1. Reference the EJB project in Project References.
  2. Add EJB project in Web Deployment Assembly.
With the code flat on the plane, I think I have spotted the error. Notice that both web and EJB project having the same class name (Authentication) and package name (org.huahsin), this is where the error came from. Thus, rework on the code by placing org.huahsin.ejb for EJB project and org.huahsin.web for web project will solve this issue.

Sunday, October 25, 2015

There are two JNDI binding for EJB

This is so ridiculous, now only I got to realize there are two types of EJB JNDI context available when connecting the client to the server. Assuming I have the following JNDI binding ready:
   java:global/ejb1/AuthenticationImpl!org.huahsin.AuthenticationRemote
   java:app/ejb1/AuthenticationImpl!org.huahsin.AuthenticationRemote
   java:module/AuthenticationImpl!org.huahsin.AuthenticationRemote
   java:jboss/exported/ejb1/AuthenticationImpl!org.huahsin.AuthenticationRemote
   java:global/ejb1/AuthenticationImpl
   java:app/ejb1/AuthenticationImpl
   java:module/AuthenticationImpl
The first is org.jboss.naming.remote.client.InitialContextFactory, this will require additional library, jboss-client.jar to be loaded in the classpath. And also this is the most hassle free and easy to setup. The following code shows how this could be done:
   Properties props = new Properties();
   props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
   props.put(Context.PROVIDER_URL, "remote://127.0.0.1:4447");

   InitialContext context = new InitialContext(props);

   AuthenticationRemote bean = (AuthenticationRemote) context.lookup("ejb1/AuthenticationImpl!org.huahsin.AuthenticationRemote");
The second is org.jboss.ejb.client.naming, it consists of two parts. The first is the setup in the code, as shown in the following:
   Hashtable props = new Hashtable();
   props.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
  
   InitialContext context = new InitialContext(props);

   String appName = "";
   String moduleName = "ejb1";
   String distinctName = "";
   String beanName = AuthenticationImpl.class.getSimpleName();
   String interfaceName = AuthenticationRemote.class.getName();
   String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + interfaceName;
  
   AuthenticationRemote bean = (AuthenticationRemote) context.lookup(name);
The second part would be the configuration file, jboss-ejb-client.properties, to be placed in the classpath. Missing this would not be able to establish connection to the server. The content of the configuration is as follows:
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
 
remote.connections=default
 
remote.connection.default.host=127.0.0.1
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
Phew! Finally, I got the things clear.

Thursday, October 22, 2015

org.jboss.naming.remote.client.InitialContextFactory was not found in JBoss server runtime

The same piece of code, execute on different PCs, I'll have different results.
 Properties props = new Properties();
 props.put("java.naming.factory.url.pkgs", "org.jboss.ejb.client.naming");
 props.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
 props.put("java.naming.provider.url", "remote://127.0.0.1:4447");
 props.put("jboss.naming.client.ejb.context", "true");
 props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT","false");

 InitialContext context = new InitialContext(props);

The above code was compiled and execute successfully without error. But when I move the piece to another PC, the compilation will fail and following error would be seen.
Caused by: java.lang.ClassNotFoundException: org.jboss.naming.remote.client.InitialContextFactory
 at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:274)
 at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:72)
 at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:61)
 at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:671)
 ... 4 more
Although I do have already configured JBoss EAP 6 as the server runtime in my project configuration, unfortunately none of the JARs found the org.jboss.naming.remote.client.InitialContextFactory class. Actually, this class can be found in jboss-client.jar and it was so unlucky that it has been excluded being a member of Jboss server runtime. Sigh... Thus, I have to explicitly include this JAR into the classpath and it is easily found in <jboss_root>\bin\client.

Sunday, April 12, 2015

Operation failed with status WAITING

My first learning objective on EJB is to establish a connection to the server and then return a value, say 5063, to the client. Thus, I have the following piece on server side:
@Remote
public interface AuthenticationRemote {

 public int status();
}


@Stateless
@LocalBean
public class Authentication implements AuthenticationRemote {

    /**
     * Default constructor. 
     */
    public Authentication() {
    }

 @Override
 public int status() {
  return 5063;
 }

}
The project name for the pieces above, ejb2, will be the context path used by a client to identify the remote path of a specific method call. When the piece is deployed to the server, following log would be seen:
java:global/ejb2/Authentication!org.huahsin.AuthenticationRemote
java:app/ejb2/Authentication!org.huahsin.AuthenticationRemote
java:module/Authentication!org.huahsin.AuthenticationRemote
java:jboss/exported/ejb2/Authentication!org.huahsin.AuthenticationRemote
java:global/ejb2/Authentication!org.huahsin.Authentication
java:app/ejb2/Authentication!org.huahsin.Authentication
java:module/Authentication!org.huahsin.Authentication
On the client side, as in following piece, is a separate project which will establish a connection to the above piece:
public class EjbClient {

 public static void main(String args[]) throws NamingException {
  Properties props = new Properties();
  props.put("java.naming.factory.url.pkgs", "org.jboss.ejb.client.naming");
  props.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
  props.put("java.naming.provider.url", "remote://127.0.0.1:4447");
  props.put("jboss.naming.client.ejb.context", "true");
  props.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT","false");
  
  InitialContext context = new InitialContext(props);
  
  String appName = "";
  String moduleName = "ejb2";
  String distinctName = "";
  String beanName = Authentication.class.getSimpleName();
  String interfaceName = AuthenticationRemote.class.getName();
  String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + interfaceName;
  
  AuthenticationRemote bean = (AuthenticationRemote) context.lookup(name);
  int result = bean.status();
 }
}
I was so unlucky that I was failed to establish a connection to server. End I up I get this:
Exception in thread "main" javax.naming.NamingException: Failed to create remoting connection [Root exception is java.lang.RuntimeException: Operation failed with status WAITING]
 at org.jboss.naming.remote.client.ClientUtil.namingException(ClientUtil.java:36)
 at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:121)
 at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684)
 at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
 at javax.naming.InitialContext.init(InitialContext.java:242)
 at javax.naming.InitialContext.(InitialContext.java:216)
 at org.huahsin68.EjbClient.main(EjbClient.java:21)
Caused by: java.lang.RuntimeException: Operation failed with status WAITING
 at org.jboss.naming.remote.protocol.IoFutureHelper.get(IoFutureHelper.java:89)
 at org.jboss.naming.remote.client.NamingStoreCache.getRemoteNamingStore(NamingStoreCache.java:56)
 at org.jboss.naming.remote.client.InitialContextFactory.getOrCreateCachedNamingStore(InitialContextFactory.java:166)
 at org.jboss.naming.remote.client.InitialContextFactory.getOrCreateNamingStore(InitialContextFactory.java:139)
 at org.jboss.naming.remote.client.InitialContextFactory.getInitialContext(InitialContextFactory.java:104)
 ... 5 more
But later I found out I forgot to turn on my server. Finally, the result variable is returning the value of 5063.