WebServices subsystem disabled in Wildfly 23/24 (Jakarta JWS) - java

I am trying to deploy an extremely simple SOAP Web Service, using Jakarta JWS 3.0.0 on OpenJDK 15, to a clean Wildfy 23/24 instance. The code is as follows:
Interface:
import jakarta.jws.WebMethod;
import jakarta.jws.WebService;
import jakarta.jws.soap.SOAPBinding;
import jakarta.jws.soap.SOAPBinding.Style;
#WebService
#SOAPBinding(style = Style.RPC)
public interface HelloWorldServerInt {
#WebMethod
String sayHelloWorld(String name);
}
Implementation:
import jakarta.jws.WebService;
#WebService(endpointInterface = "ws.HelloWorldServerInt")
public class HelloWorldServerImpl implements HelloWorldServerInt {
#Override
public String sayHelloWorld(String name) {
return "Hello World ! My name is " + name + ".";
}
}
Once I deploy the WAR, I can see it under "Deployments" in the admin console. But if you click "Views / Management Model", under "subsystem", the "webservices" subsystem is disabled, so I cannot see the deployed service, and of course it doesn't work.
I've worked with Web Services before using web.xml file and com.sun.xml.ws.transport.http.servlet.WSServlet servlet, but as far as I know, this is not the way to go, and annotations should be automatically discovered by Wildfly. Am I wrong?
Kind regards.

As #ehsavoie explained in the comments, the problem was using Wildfly 24 instead of Wildfly Preview 24.
Once everything was set up with WF Preview, Web services subsystem was enabled and usable as expected.

Related

How can I customize spring boot embedded tomcat thread pool?

Tomcat architecture is comprised of the following elements: Server => Service => Engine => Host => Context
When configuring a standard Tomcat server, we can configure a custom thread pool by specifying the following in our server.xml file: (below is pseudo-code)
<Server>
<Service name="Catalina">
<Connector port="8080"/>
<Executor name="custom-pool" className="my.package.poolImplementation" />
<Engine name="Catalina" defaultHost="localhost">
<Here be more elements />
</Engine>
</Service>
</Server>
(specifically, the Executor name="custom-pool" className="my.package.poolImplementation")
How do I configure Spring Boot to allow the same behaviour programmatically ?
(WITHOUT using Spring configuration files)
No matter where i searched, or how hard I tried, I couldn't find any answer or example.
Thanks in advance
I looked up some source code (see TomcatServletWebServerFactory.java/ServletWebServerFactoryConfiguration.java) and found a way to do that.
#Bean
public TomcatProtocolHandlerCustomizer<?> tomcatProtocolHandlerCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(...);
};
}
I needed to customize Tomcat also.
I ended up with a code like this:
#Component
public class TomcatCustomizer extends TomcatServletWebServerFactory {
#Override
protected void postProcessContext(Context context) {
Engine engine = (Engine) context.getParent().getParent();
Service service = engine.getService();
Server server = service.getServer();
Connector connector = service.findConnectors()[0];
}
}
You can then set different properties of the server, service, engine, connector.
From the object service you can also access the executor and change it.
This part I never tried.
Whatever you change it will override and complete the spring-boot configuration, you will not loose the spring-boot config.
As Yonatan mentioned one can add an executor with
service.addExecutor(...)
there is also a method from removing an executor.
I needed this kind of detailed access to the configuration because I needed to configure the server.getGlobalNamingResources().
Also to add a JAASRealm and a Valve.
I do not see how one could achieve complete config access with just the customize method.
Considering two and a half years have passed since I originally asked this question, I think it is time that I shared our solution for the benefit of anyone that might read this in the future.
We ended up writing a custom component that implements WebServerFactoryCustomizer. Spring Boot will scan for all beans before starting its embedded Tomcat server. If it detects a bean that implements this interface, it will invoke the customize() method and pass the server factory as an argument to the function.
From there, it was straightforward:
package your.pack.age.name;
import org.apache.catalina.core.StandardThreadExecutor;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
#Component
public class TomcatServerConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
private final StandardThreadExecutor customExecutor;
public TomcatServerConfig() {
this.customExecutor = YourExecutorImplementation();
}
#Override
public void customize(TomcatServletWebServerFactory factory) {
/*This web server is the Tomcat server embedded in Spring Boot*/
TomcatWebServer webServer = (TomcatWebServer)factory.getWebServer()
webServer.getTomcat().getService().addExecutor(this.customExecutor);
}
}
(The actual code we used was simplified here, for the sake of a clear answer)
It is also worth noting that similar code needs to be written for the Tomcat Connectors, using TomcatConnectorCustomizer:
package your.pack.age.name;
import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.stereotype.Component;
#Component
public class TomcatConnectorConfig implements TomcatConnectorCustomizer {
private final StandardThreadExecutor customExecutor;
public TomcatConnectorConfig() {
this.customExecutor = YourExecutorImplementation();
}
#Override
public void customize(Connector connector) {
connector.getProtocolHandler().setExecutor(this.customExecutor);
}
}

JAX-WS service deployment

I am new to web service programming and trying to create a JAX-WS web-service. I have created the following JAX-WS web service in Eclipse:
Creating the service interface:
package test;
#WebService
#SOAPBinding(style = Style.RPC)
public interface AdditionService {
#WebMethod
int add(int a,int b);
}
After that one implementation class:
package test;
#WebService(endpointInterface = "test.AdditionService")
public class AdditionServiceImpl implements AdditionService{
#Override
public int add(int a, int b) {
return a+b;
}
}
Last step:
By using the following code I am publishing the service:
package test;
public class AddtionServicePublisher {
public static void main(String[] args) {
Endpoint.publish
("http://localhost:9999/ws/additionService",
new AdditionServiceImpl());
}
}
I can view the wsdl using the bellow local URL:
http://localhost:9999/ws/additionService?wsdl
But as I don't have any server installed. How, it is getting published? Is server is inbuilt with eclipse?
The Oracle Java documentation states the following
Creates and publishes an endpoint for the specified implementor object at the given address.
The necessary server infrastructure will be created and configured by the JAX-WS implementation using some default configuration.
As JAX-WS is part of the Java SE package, this means the underlying server is depending on what kind of JVM you are running your program at. E.g. on my laptop I am running a Java 8 OpenJDK, in which an instance of "com.sun.net.httpserver.HttpServer" is created.
The fastest way to find out what server ist started in your environment, just jump into the (decompiled) code of the Endoint.java and the implementation(s).
If you want to create a standalone, selfrunning Webservice-jar you might be interested to take a look at Spring-WS (with Spring Boot) or Dropwizard.

JNDI loopup for a remote client accessing an EJB deployed in JBOSS AS (7.1.1 final)

I have created a simple EJB 3.0 application, deployed in JBOSS 7.1.1 final.
Here is the code:
EJB 1:
Interface
package com.example.server.local.bean;
import javax.ejb.Local;
#Local
public interface UtilLocalBeanLocal {
public String addString();
}
Class implementing this interface:
package com.example.server.local.bean;
import javax.ejb.Local;
import javax.ejb.Stateless;
#Stateless
#Local(value=UtilLocalBeanLocal.class)
public class UtilLocalBean implements UtilLocalBeanLocal {
public UtilLocalBean() {
}
#Override
public String addString() {
return "Added from Local bean";
}
}
So, this EJB i am creating to be "locally" used by another EJB.
EJB 2:
Interface
package com.example.bean.session;
import javax.ejb.Remote;
#Remote
public interface FirstBeanRemote {
public String callMe();
}
Class implementing this interface.
package com.example.bean.session;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import com.example.server.local.bean.UtilLocalBeanLocal;
#Stateless
#Remote(value=FirstBeanRemote.class)
public class FirstBean implements FirstBeanRemote {
#EJB
private UtilLocalBeanLocal utilLocalBeanLocal;
public FirstBean() {
}
#Override
public String callMe() {
return "Hi there!" + utilLocalBeanLocal.addString();
}
}
When i start the JBOSS, the JNDI bindings i get are like this:
00:34:15,928 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-5) JNDI bindings for session bean named FirstBean in deployment unit subdeployment "EJB30TestProj.jar" of deployment "EJB30TestProjEAR.ear" are as follows:
java:global/EJB30TestProjEAR/EJB30TestProj/FirstBean!com.example.bean.session.FirstBeanRemote
java:app/EJB30TestProj/FirstBean!com.example.bean.session.FirstBeanRemote
java:module/FirstBean!com.example.bean.session.FirstBeanRemote
java:jboss/exported/EJB30TestProjEAR/EJB30TestProj/FirstBean!com.example.bean.session.FirstBeanRemote
java:global/EJB30TestProjEAR/EJB30TestProj/FirstBean
java:app/EJB30TestProj/FirstBean
java:module/FirstBean
However in the remote client when I try to use any of these above JNDI binding values, it is not working, and what actually works (after lot of google) is:
ejb:EJB30TestProjEAR/EJB30TestProj//FirstBean!com.example.bean.session.FirstBeanRemote
It is difficult to understand how this JNDI bindings work. JBOSS outputs a different JNDI and in reality what works is different one.
Can anyone please demystify this? (how to decide which JNDI bindings will work in different scenarios and any further pointers)
The binding values that you mention are prepared for lookup locally, let say into the server that you publish the ejb. global, module, app are the scopes limit and in which you can use each one. For example, you could lookup a ejb from other ejb of the same ejb-module using module scope but you couldn't lookup it from another ejb-module even being modules of the same app (ear or war), you must use at least app scope for that, and you can use app or global in both scenarios.
I strongly suggest you to take the time to read Jboss AS7 JNDI Referencia but to know about remote lookup go to Remote JNDI section

Expose EJB as JAX-RS service

I have a problem when i want to expose my EJB Project as JAX-RS service. I've tried to find a solution many times but i've not fixed it. I've succeeded deploy my application but i didn't found my rest service in localhost:4848 => Applications => My_Application. Normally, if a rest service is deployed, there is "Launch" button.
I use glassfish4 and eclipse Java EE.
My EJB Project is like that:
Package ejb: TestSessionBean.java
Package rest: RestTest.java and RestTestApp.java
TestSessionBean.java
#Path("/peter")
#Stateless
#LocalBean
public class TestSessionBean {
public TestSessionBean() {
// TODO Auto-generated constructor stub
}
#GET
public String sayHello() {
return "Hello";
}
}
RestTest.java
#Path("/ep")
public class RestTest {
#GET
public String sayBonjour() {
return "Bonjour";
}
}
RestTestApp.java
#ApplicationPath("/test/*")
public class RestTestApp extends Application {
}
I also tried to config my project: Properties => Project Facets => enable JAX-RS (but when i clicked on "Further configuration available", i had "Type: Disable Library Configuration".
I tried localhost:8080/ejbtest/test/peter/ and localhost:8080/ejbtest/test/ep but both didn't work.
But if i create a new Dynamic Web Project all and copy all of my source files in ejbtest into this project. It works! So i think about something to do in eclipse configuration of ejb project. Any solution?
Thank you in advanced.

ValidationEventHandler JBOSS 7.2.x

JBOSS 7.x has the possibility to activate schema validation on the server side by means of using an #SchemaValidation annotation on the SEI.
However I would like to customize my errors as well. Moreover I would like to change the exception into a report (result).
I've found the following question / answer on Stack Overflow. Which explains how to setup a customized ValidationEventHanlder with CXF. However, JBOSS uses it own way deployment descriptors overriding the CXF ones. It is possible to achieve the same result as with the #Schemavalidation by means of the JBOSS web service deployment descriptor. However, I was not able yet to activate my own event handler.
I'm thinking about not throwing an exception, but storing the validation result in a HTTP header or in a ThreadLocal, in order to create my own result.
Questions:
1) Is it possible to setup a ValidationEventHander in JBOSS 7.x.x (or in JBOSS 6.x.x EAP)?
2) Is it possible to override the default exception (not throwing an exception on non-fatal errors, like ranges, formats etc?) and returning a result?
Thanks!
JBOSS 7.x uses a concept called 'interceptors'. By defining an interceptor one can access the message context. There are 2 flavours of messsage contexts:
The WebService Context that is available via the #Resource annotation in the Servlet or EJB
The CXF WebService Context that is avialable to 'later interceptors' in the chain.
The latter one is available by menas of the setContextualProperty.
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.ValidationEvent;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class ValidatingInterceptor extends AbstractPhaseInterceptor<Message> {
public static String CTX_KEY_VALIDATOR_EVENTS = "event_key";
public ValidatingInterceptor() {
super(Phase.READ);
}
#Override
public void handleMessage(Message message) throws Fault {
List<ValidationEvent> validationRes = new ArrayList<ValidationEvent>();
message.put(CTX_KEY_VALIDATOR_EVENTS, validationRes);
message.setContextualProperty("jaxb-validation-event-handler", new XmlValidationHandler(validationRes));
}
}
Here is the validator that is inserted:
import java.util.List;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
public class XmlValidationHandler implements ValidationEventHandler {
private final List<ValidationEvent> results;
public XmlValidationHandler(List<ValidationEvent> results) {
this.results = results;
}
#Override
public boolean handleEvent(ValidationEvent event) {
results.add(event);
return true;
}
}
The validator adds a List to the context described in 1. and is now available for further processing in the EJB or Servlet. The SEI then looks like this:
#SchemaValidation
#InInterceptors(classes = {ValidatingInterceptor.class})
#Stateless
public class LogicBean implements SEI
Note: the #SchemaValidation is still required as annotation, since that triggers the annotation in the first place.

Categories