Hot questions for Using Enterprise JavaBeans in web services

Question:

I am migrating a statless EJB exposed as a web service from JBoss7 AS to WildFly 10 (granted I am a bit late).

The web service used to be accessible by http://localhost:8080/vmwWS/vmw, moving to WildFly gets me http://localhost:8080//vmwWS/WSVMWBean and I haven't found a way to change this.

Here's the web service class

[...]
@Interceptors(TracingInterceptor.class)
@Stateless
@WebService(endpointInterface = "com.mydomain.WSVMW")
@WebContext(contextRoot="/vmwWS", urlPattern ="/vmw", authMethod="BASIC", secureWSDLAccess = false)
@SecurityDomain("JBossWS")
@RolesAllowed({ "Read", "Write" })
public class WSVMWBean implements WSVMW {
[...]

The Interface:

[...]
@WebService(name = "vmw")
@SOAPBinding(style = Style.DOCUMENT)
@Local
public interface WSVMW {
[...]

And the jboss-webservice.xml:

<?xml version="1.0" encoding="UTF-8"?>
<webservices xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.com/xml/ns/javaee/jbossws-web-services_1_0.xsd"
version="1.1">
  <context-root>vmwWS</context-root> 
   <port-component>
    <ejb-name>WSVMWBean</ejb-name>
    <port-component-name>WSVMWBean</port-component-name>
    <port-component-uri>/vmw</port-component-uri>
    <auth-method>BASIC</auth-method>
  </port-component>
</webservices>

The logs say:

22:16:59,520 INFO  [org.jboss.ws.cxf.metadata] (MSC service thread 1-8) JBWS024061: Adding service endpoint metadata: id=WSVMWBean
 address=http://localhost:8080/<ejb-jar-name>/vmwWS/WSVMWBean
 implementor=com.mydomain.WSVMWBean
 serviceName={http://vmw.mydomain.com/}/vmwWS
 portName={http://vmw.mydomain.com/}WSVMWBeanPort
 annotationWsdlLocation=null
 wsdlLocationOverride=null
 mtomEnabled=false

How do I get the previous behaviour back?


Answer:

To cut it short this is the diff which fixed it:

-import org.jboss.wsf.spi.annotation.WebContext;
+import org.jboss.ws.api.annotation.WebContext;

From here: https://developer.jboss.org/wiki/JBossWS4MigrationGuide

Question:

My goal is to create Java EE web service, which will take concurrently thousands (or more in future) requests and must store data from requests in list or similar structure. I want to store objects from requests in memory, but this is not obligatory. Some object will be extracted from every request and added to chosen data structure. Web service will have two operations: add to structure and remove from structure. Removal request will contain values of object instance variables. Probably it will be unique ID or other one or more instance variables. There will be always one object to remove (or 0 if request is not valid). Object with equal instance variable(s) value will be removed.

My thought is to use two EJBs. First would be @Stateless and exposed as web service. It would extract object from request and call second EJB to add or remove requested object from data structure. Second EJB would be @Singleton and would have instance variable ArrayList<> of objects extracted from requests. As I said it doesn't have to be ArrayList or List at all.

I have also thought about using one EJB, which would have to be @WebService @Singleton, but documentation says that this combination is "possible, but ... not defined by this specification."


Answer:

Arjan, your requirement is not fully clear. Assuming you are building a high load application > 1000 request per second I would do:

Servlet-processing

  • separate the "object" datacontainers into the http session of each user (if http session is available)
  • add a synchronized List into you http session and on every request do the operations on a synchronized private List and add the web client details to this http session stored list
  • add a reference of the httpsession list to the next mentioned SingletonEJB

Singleton EJB

  • create a singleton EJB
  • add a List field for your extracted/filtered/processed Objects of YourObjectType type
  • add a second Collection for the references of the HTTP-Session based and unfiltered but synchronized List

TimerEJB

  • create a timer EJB to run periodically e.g. every second
  • this function will go through all referenced Lists in the refCol and will extract and filter the needed objects and also ensure to make a cleanup of the http session based lists.

Benefit of the solution:

  • push the mem load of the users to their sessions
  • do not get into synchronizing/mutex issues on very high load, since you operate only very short with your timerEJB on a central and filtered List in your Singleton bean.
  • you are as long scaleable as long your sessions keep small
  • the maybe CPU intensive solution to filter and the IO intensive solution to persist the filtered objects are outside the client requests and the clients will not face an performance issue.
  • the timer schedules are changeable by your needs

Drawback:

  • a little higher complexity
  • you have to clean your references in your refColl to the Lists of the closed http sessions. Either by providing also the Session and the Reference to the List of the session in a composite class or by any other custom solution. If you do not cleanup, your heap will get bloated by holding references to Lists of already "killed" http sessions.

Question:

I have a WSDL file which defines an event operation.

Need to define a SOAP web service end point which is called by a third-party with some parameters as specified in a WSDL file.

The project uses EJB 2.1

CanĀ“t get the end point to work (404 error):

http://localhost:28080/myapp/ws/ClassCallBack

The classes below are inside a JAR file included in the root folder of the EAR file.

Is there anything wrong ? Do I have to declare this class as an EJB in some xml? (in ejb-jar.xml , all EJB Session Beans are declared, but this is not a session bean)

@WebService
public interface ClassCallBackWs {

@WebMethod
  public void event(@WebParam(name = "event") ClassParameter event) 
      throws Exception;      
}

=====================================

@Stateless(name = "ClassCallBackEjb")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@WebService(name = "ClassCallBackWs", portName = "ClassCallBackWs",
        serviceName = "ClassCallBackWsService",
        targetNamespace = "http://test.serverurl.org.com/",
        endpointInterface = "ClassCallBackWs")
@WebContext(contextRoot = "/myapp/ws/", 
            urlPattern = "/v0/ClassCallBackWsImpl", 
            transportGuarantee = "NONE", secureWSDLAccess = false)
public class ClassCallBackWsImpl implements ClassCallBackWs {

    @WebMethod
    public void event(@WebParam(name = "event") ClassParameter event) throws Exception {
    }

}

Answer:

Give below an example of one possible solution. Created a custom servlet which has a mapping to the implementation class by defining a JAX WS end point in its XML

(Have concealed all names relating to the final solution, as is private-owned. Sorry if there is a mistake because of this).

Servlet mapping / XML:

<servlet-mapping>
    <servlet-name>testws</servlet-name>
    <url-pattern>/myapp/ws/v0/</url-pattern>
</servlet-mapping>

XML configuration for the servlet used as End Point:

    <jaxws:endpoint
        id="CallBackWs" implementor="org.test.ClassCallBackWsImpl "
        wsdlLocation="WEB-INF/wsdl/CallBackTest.wsdl"
        address="/ClassCallBackWsImpl"
        bindingUri="ClassCallBackWsImpl">
    </jaxws:endpoint>

End point Impl Class:

   @WebService(
      portName = "CallBackWs",
      serviceName = "CallBackWsService", 
      targetNamespace = "http://test.server.callback.ws/", 
      endpointInterface = "org.test.CallBackWs") 
   public class ClassCallBackWsImpl implements ClassCallBackWs{    
       public void event(ClassParameter event) throws Exception { 
       } 
   }

Interface class:

@WebService(targetNamespace = "http://test.server.callback.ws/", name = "ClassCallBackWs")
public interface Ws {
    @RequestWrapper(localName = "event", targetNamespace = "http://test.server.callback.ws/", className = "org.test.ClassParameter")
    @WebMethod
    public void event(
        @WebParam(name = "event", targetNamespace = "")
        org.test.ClassParameter event
    ) throws Exception;
}

Question:

I have a big problem, for me who is very very very new in Web Service. In a package of a project A, i have a proxy. In this proxy (which is an EJB), i "injected" an EJB called referenceWebService via the annotation @EJB(name = "xxxxx"). referenceWebService corresponds to an interface (annotated @WebService) located in project A which is implemented by a class (annotated @WebService) in an other project.

<code>
@Stateless(name = "zzzzzzz")
public class MyProxy {
  @EJB(name = "xxxxx")
  myEJBType referenceWebService;
}
</code>

In a package of an other project B, i have my WebService (an EJB also) - the implementation of my Web Service - annotated with @WebService : the wsdl of this web service is automatically generated by the JBoss server. For this Web Service, i put value only for these 2 attributes of @WebService : targetNameSpace and name). The link between the 2 differents projects is made because in the project A, i have a package called api where i put the interface referenceWebService, and the implementation of this interface is in the project B. The call of the Web Service, in project A, does not work. I am looking for a very simple solution. When i see the JSR, i understand that i have to use the class javax.xml.ws.Service. Is it a good way ? And, if yes, i have replace the attribute called referenceWebService in the proxy, by an other which extends the javax.xml.ws.Service ? When i replace in the proxy, for the attribute called referenceWebService, the @EJB annotation by the @WebServiceRef annotation, it does not work. Thank you very much for your help.


Answer:

Like i wanted, i have created a class which extends the class javax.xml.ws.Service I wrote this question because i was not certain, but, now, after reading documentation about Web Services, i am certain. I have to use an instance of this class as a reference of my Web Service.