I have an application in Java that uses CXF to make calls to a web service. The code for the initiator looks like
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.tempuri.IAPIService;
import javax.inject.Inject;
/**
* Created by flavius on 23/09/14.
*/
#Component()
public class VsJaxWsProxyFactory {
#Inject
private Environment env;
private JaxWsProxyFactoryBean factoryBean = null;
public Object create() {
if (factoryBean == null) {
factoryBean = new JaxWsProxyFactoryBean();
factoryBean.setServiceClass(IAPIService.class);
factoryBean.setAddress(env.getProperty("api.wsdl"));
}
return factoryBean.create();
}
}
The application runs fine, but after a while the box starts to consume too much memory and the application starts running slow. When we tried to do a memory analysis we found the following
It seems that the CXF is somehow creating a new Service configuration object on each call, and is not being released. I can't find much information on org.apache.cxf.jaxws.support.JaxWsServiceConfiguration class and not sure if this is a configuration issue or some internal bug in some library.
Already answered here:
Apache CXF not releasing clients
Basically .create() method on the same JaxWsProxyFactoryBean instance should be called only once, otherwise you get a memory leak:
return factoryBean.create();
factoryBean.create() returns the cxf JAX-WS client proxy, which you can reuse for repeated calls. Created client is also thread safe if you don't use any special features mentioned here http://cxf.apache.org/faq.html#FAQ-AreJAX-WSclientproxiesthreadsafe?
Related
I'm getting started with micronaut and I would like to understand the difference between testing the controller using local host and using an Embedded server
For example
I have a simple controller
#Controller("/hello")
public class HelloController {
#Get("/test")
#Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
and the tested class
#MicronautTest
public class HelloControllerTest {
#Inject
#Client("/hello")
RxHttpClient helloClient;
#Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/test");
String body = helloClient.toBlocking().retrieve(request);
assertNotNull(body);
assertEquals("Hello World", body);
}
}
I got the logs:
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Sending HTTP Request: GET /hello/test
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Chosen Server: localhost(51995)
But then, in which cases we need an Embedded Server? why?
where I can find documentation to understand it. I read the documentation from Micronaut but is not clear for me, what is actually occurring and why?
like this example:
#Test
public void testIndex() throws Exception {
EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);
RxHttpClient client = server.getApplicationContext().createBean(RxHttpClient.class, server.getURL());
assertEquals(HttpStatus.OK, client.toBlocking().exchange("/hello/status").status());
server.stop();
}
In both cases, you are using EmbeddedServer implementation - NettyHttpServer. This is an abstraction that represents Micronaut server implementation (a NettyHttpServer in this case).
The main difference is that micronaut-test provides components and annotations that make writing Micronaut HTTP unit tests much simpler. Before micronaut-test, you had to start up your application manually with:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
Then you had to prepare an HTTP client, for instance:
HttpClient http = HttpClient.create(server.URL)
The micronaut-test simplifies it to adding #MicronautTest annotation over the test class, and the runner starts the embedded server and initializes all beans you can inject. Just like you do with injecting RxHttpClient in your example.
The second thing worth mentioning is that the #MicronautTest annotation also allows you to use #MockBean annotation to override existing bean with some mock you can define at the test level. By default, #MicronautTest does not mock any beans, so the application that starts reflect 1:1 application's runtime environment. The same thing happens when you start EmbeddedServer manually - this is just a programmatic way of starting a regular Micronaut application.
So the conclusion is quite simple - if you want to write less boilerplate code in your test classes, use micronaut-test with all its annotations to make your tests simpler. Without it, you will have to manually control all things (starting Micronaut application, retrieving beans from application context instead of using #Inject annotation, and so on.)
Last but not least, here is the same test written without micronaut-test:
package com.github.wololock.micronaut.products
import io.micronaut.context.ApplicationContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
class ProductControllerSpec extends Specification {
#Shared
#AutoCleanup
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
#Shared
#AutoCleanup
HttpClient http = server.applicationContext.createBean(RxHttpClient, server.URL)
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
In this case, we can't use #Inject annotation and the only way to create/inject beans is to use applicationContext object directly. (Keep in mind that in this case, RxHttpClient bean does not exist in the context and we have to create it - in micronaut-test case this bean is prepared for us upfront.)
And here is the same test that uses micronaut-test to make the test much simpler:
package com.github.wololock.micronaut.products
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
#MicronautTest
class ProductControllerSpec extends Specification {
#Inject
#Client("/")
HttpClient http
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
Less boilerplate code, and the same effect. We could even #Inject EmbeddedServer embeddedServer if would like to access it, but there is no need to do so.
I'm creating a REST web application with Java, Tomcat and Jersey. I'm using annotations (no web.xml!) I ended up using this application configuration:
package com.my_own.server;
import java.util.Properties;
import javax.ws.rs.ApplicationPath;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.my_own.db.PostgreSQLDb;
#ApplicationPath("/api")
public class Application extends javax.ws.rs.core.Application {
private static Logger logger = LogManager.getLogger(Application.class);
public static Application application = null;
public final Properties properties;
public final PostgreSQLDb adminDb;
public Application() throws Exception {
logger.debug("Loading properties from ",
getClass().getClassLoader().getResource("config.properties"));
properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("config.properties"));
adminDb = new PostgreSQLDb(properties, "admin");
application = this; // Setting the global application object here
}
}
Here is my problem. There is a single global application objects for the web container. I'm saving it into a static field, from the application constructor. I need to access it from other classes later (it holds the global configuration, a global database connection factory, and probably other things.)
Am I doing this right? I suspect that there must be a better way: save a reference to the application when annotations are processed. But I'm not sure how. Can I be sure that the Application's constructor will be called exactly once, and the Application.application reference can be accessed later, from any REST call?
Use dependency injection in jersey, bind your application when initializing:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyApplication.class);
register(new MyBinder());
packages(true, "location.of.my.jersey.classes");
}
/* Bind is used to let jersey know what can be injected */
private static class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyApplication.class).to(MyApplication.class);
}
}
}
Then in your code:
#Path("myapi")
#Produces(MediaType.APPLICATION_JSON)
public class ServerRoutes {
#Inject
MyApplication application;
//... your rest code here
}
Now you can access MyApplication from within your code without needing any statics or singletons, jersey handles it.
Let me share my opinion: you can use of course a well-known Singleton pattern to store a "global" static object, however, it's really an antipattern these days.
If it's not a homework or something then storing global "static" objects is always a bad idea design-wise. If you want to know why there are many sources that answer this question, like this discussion for example
So I suggest considering using a Dependency Injection container instead, There are many really good containers out there: Spring, Guice to name a few.
These containers can store these objects as beans and if your "pieces" of functionality are also managed by these containers, you'll be able to "inject" application beans right into the controller.
It effectively solves all the issues introduced by singleton pattern.
I have a Spring Boot Apache CXF web application. It is running just fine. However whenever I close down the application I get a warning about a nullpointer from the ApplicationListener handling ContextClosedEvent. It looks like it might be related to the Apache CXF bus.
11:10:24.728 INFO [Thread-10][AnnotationConfigEmbeddedWebApplicationContext] Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#39b667c3: startup date [Thu May 11 11:09:48 PDT 2017]; root of context hierarchy
11:10:24.738 WARN [Thread-10][AnnotationConfigEmbeddedWebApplicationContext] Exception thrown from ApplicationListener handling ContextClosedEvent
java.lang.NullPointerException: null
at java.util.concurrent.ConcurrentHashMap.replaceNode(ConcurrentHashMap.java:1106)
at java.util.concurrent.ConcurrentHashMap.remove(ConcurrentHashMap.java:1097)
at org.apache.cxf.transport.http.DestinationRegistryImpl.removeDestination(DestinationRegistryImpl.java:63)
at org.apache.cxf.transport.http.AbstractHTTPDestination.deactivate(AbstractHTTPDestination.java:961)
at org.apache.cxf.transport.AbstractObservable.setMessageObserver(AbstractObservable.java:65)
at org.apache.cxf.endpoint.ServerImpl.stop(ServerImpl.java:174)
at org.apache.cxf.endpoint.ServerImpl.destroy(ServerImpl.java:180)
at org.apache.cxf.bus.managers.ServerRegistryImpl.preShutdown(ServerRegistryImpl.java:90)
at org.apache.cxf.bus.managers.CXFBusLifeCycleManager.preShutdown(CXFBusLifeCycleManager.java:97)
at org.apache.cxf.bus.extension.ExtensionManagerBus.shutdown(ExtensionManagerBus.java:326)
at org.apache.cxf.bus.extension.ExtensionManagerBus.shutdown(ExtensionManagerBus.java:313)
at org.apache.cxf.bus.spring.SpringBus.onApplicationEvent(SpringBus.java:109)
at org.apache.cxf.bus.spring.SpringBus$1.onApplicationEvent(SpringBus.java:58)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:166)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:382)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:336)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:989)
at org.springframework.context.support.AbstractApplicationContext$2.run(AbstractApplicationContext.java:923)
11:10:24.780 INFO [Thread-10][AnnotationMBeanExporter] Unregistering JMX-exposed beans on shutdown
Here is a class I wrote that I think the error may be stemming from, but I am not sure.
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
#Configuration
public class EndpointConfig {
#Autowired
private Bus bus;
#Autowired
private AmazonS3 s3client;
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus,
new AcmeWebServiceImpl(s3client));
endpoint.publish();
return endpoint;
}
#Bean
public AmazonS3 amazonS3(){
AmazonS3 amazonS3 = AmazonS3ClientBuilder.defaultClient();
return amazonS3;
}
}
I am posting this as an answer, maybe it helps someone else also.
Yes, I did manage to fix it … after 3 days of trying … it’s more like a workaround, maybe fix is too much to say, since the fix should be probably done in the cxf code… Actually our stack trace was a little different, I am attaching it below. Similar until a certain point, so maybe how we fixed it could be of some help to you. Here it is:
What we noticed was that in DestinationRegistryImpl- removeDestination method, line #63, the path that was being removed from the ConcurrentHashmap was null and this came from one level up AbstractHTTPDestination.deactivate(AbstractHTTPDestination.java:965). In our case we used an instance of ServletDestination (a child of AbstractHTTPDestination) which inherited the protected variable path and had this variable set through its constructor(ServletDestination constructor) in org.apache.cxf.transport.servlet.ServletDestinationFactory - #33, where the address of the EndpointInfo instance was being set as the path.
All we had to do is set an address to our endpoint(JAXRSServerFactoryBean) and this translated as the path not being null anymore and we got rid of the NPE.
I am sorry for the legth of it, hope it makes some sense…we had 3 full days of debugging anf looking through the code of the cxf framework and that was not very nice..
We added line 74 and got rid of the NPE:
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.
I have a web service (JAX-RPC) that runs on application server (Websphere Application Server 7.0).
Normally the development process looks like this:
I write a class with web service implementation (e.g. MyService.java)
The IDE generates web service endpoint interface (e.g. MyService_SEI.java)
The IDE generates configuration XMLs
When the web service is deployed, MyService_SEI is the declared service interface and the application server instantiates a MyService instance by means of the public no-arg constructor.
But what if I want to do constructor injection (i.e. have MyService class without a no-arg constructor) or if I want to provide a dynamic proxy object which implements MyService_SEI and use that?
Is there a way I can take control of the instantiation procedure (like a filter or interceptor) to achieve this?
You can't do constructor injection as Injection always occur after the default constructor is called. If you try to use an injected reference inside the default constructor it will ALWAYS fail, there's no workaround for this as this is mandate by the specification.
So the first option you mentioned is discarded.
For the second option, using a filter or interceptor, you actually have an option. WebSphere WebServices are build using Axis2 implementation and Axis provide a way of implementing Handlers.
You can add handlers into the JAX-WS runtime environment to perform additional processing of request and response messages.
Here's a handler example, from Axis documentation:
package org.apache.samples.handlersample;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class SampleProtocolHandler implements
javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> {
public void close(MessageContext messagecontext) {
}
public Set<QName> getHeaders() {
return null;
}
public boolean handleFault(SOAPMessageContext messagecontext) {
return true;
}
public boolean handleMessage(SOAPMessageContext messagecontext) {
Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
// Include your steps for the outbound flow.
}
return true;
}
}
And than you add a handler.xml file like this:
<?xml version="1.0" encoding="UTF-8"?>
<jws:handler-chain name="MyHandlerChain">
<jws:protocol-bindings>##SOAP11_HTTP ##ANOTHER_BINDING</jws:protocol-bindings>
<jws:port-name-pattern
xmlns:ns1="http://handlersample.samples.apache.org/">ns1:MySampl*</jws:port-name-pattern>
<jws:service-name-pattern
xmlns:ns1="http://handlersample.samples.apache.org/">ns1:*</jws:service-name-pattern>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleLogicalHandler</jws:handler-class>
</jws:handler>
<jws:handler>
<jws:handler-class>org.apache.samples.handlersample.SampleProtocolHandler2</jws:handler-class>
</jws:handler>
</jws:handler-chain>
an easy method would be to make two classes. one your class with all the bells and whistles (constructor injection etc lets call it worker). and the actual service. the service would delegate what it needs to the worker class, who it can get by calling some factory method.
The factory can even look at some common db or other config to decide which run time instance (which class, what config, shared or common) so you have good separation and power
Just cause you are using one framework/ method of injection does not mean you cannot mix to make it more powerful