When I deploy and run my web service developed with JAX-WS I can see a summary page with some info on it, something like in this picture:
http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat/
For the final implementation we would like to remove this page so that a custom or a blank page is returned while still having access to the web service endpoint.
We are currently running on Tomcat.
There is a field on the WSServlet class that might do what you are looking for: JAXWS_RI_PROPERTY_PUBLISH_STATUS_PAGE (it's value is com.sun.xml.ws.server.http.publishStatusPage).
Looking at the source code from a JAX-WS download it seems that you need to set it as a context parameter in your web.xml file:
<web-app>
<context-param>
<param-name>com.sun.xml.ws.server.http.publishStatusPage</param-name>
<param-value>false</param-value>
</context-param>
...
Seems that HttpAdapter had something similar on it but was taken from an environment variable:
setPublishStatus(
System.getProperty(HttpAdapter.class.getName() + ".publishStatusPage")
.equals("true"));
The code on HttpAdapter is marked deprecated in the javadoc so the context parameter seems the way to go.
I have been trying to solve this for two days, Glassfish 3.1.2.
The only solution was to have
-Dcom.sun.xml.ws.transport.http.HttpAdapter.publishStatusPage=false
I know its old, but wantd to maintain the knowledge. Hope this helps any one with this issue.
I have completed the same task for WebLogic recently.
It was requested to hide/show a status page of a public web service depending on a target environment i.e. hide for production, show for dev.
Nothing of the previous answers worked for me.
The success solution is based on implementation of javax.servlet.Filter.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.HttpMethod;
#WebFilter(urlPatterns = { "/WeblogicWebService" })
public class FilterStatusSoapPage implements Filter {
#Value("${soap.status.page.disabled}")
private boolean flagDisablePublishStatusPage;
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
String queryString = httpReq.getQueryString();
if(flagDisablePublishStatusPage)
if(queryString == null || queryString.trim().isEmpty())
if(HttpMethod.GET.matches(httpReq.getMethod())) {
httpRes.setStatus(HttpServletResponse.SC_OK);
httpRes.getWriter().write("Access to status page of Web
Service is not allowed");
httpRes.getWriter().flush();
httpRes.getWriter().close();
return;
}
} catch (Exception e) {
System.err.println("Error on FilterStatusSoapPage filter");
chain.doFilter(request, response);
return;
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {}
public void destroy() {}
}
Related
i have a wsdl which is importing another wsdl in it.
i wanted to call the webservice from java client code, i have configured my java class as follows
package test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
#Configuration
public class WeConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("test");
return marshaller;
}
#Bean
public WeatherClient1 weatherClient(Jaxb2Marshaller marshaller) {
WeatherClient1 client = new WeatherClient1();
client.setDefaultUri("*******");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
I have my acessing method as follows
GetDataResponse response = (GetDataResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"*******",
request,
new SoapActionCallback("*******"));
My webservice would be something like
https://abcde.handling.com/celebrity/Confi?wsdl
Kindly let me know , what i have to input in setdefaultUri in configuration and soapcallbackaction. soap Ui gives me a method "GetData" for request
Thanks in advance..
Please help ..
After a long struggle , the answer for this query will be as follows;
DefaultUri = (Full WSDL) https://abcde.handling.com/celebrity/Confi?wsdl
there was no call back action for my request so:
GetDataResponse response = (GetDataResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"Imported wsdl's URI",
request);
I am creating Restful (Jax-RS) services to be deployed to Fuse 6.2.1.
(using Apache CFX, and deploying with OSGi bundles to Karaf)
The server supports only up to Spring 3.2.12.RELEASE.
I am attempting to do everything with next to zero XML configuration.
So far so good, everything is working and I can deploy and run my services.
However, I'd like to be able to test my services locally without having to deploy them. So I'd like to be able to boostrap a webserver and register my servlet, but can't quite figure our how.
I'm configuring the servlet with this (using Spring's WebApplicationInitializer rather than web.xml):
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class CxfServletInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
addApacheCxfServlet(servletContext);
}
private void addApacheCxfServlet(ServletContext servletContext) {
CXFServlet cxfServlet = new CXFServlet();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
appServlet.setLoadOnStartup(1);
Set<String> mappingConflicts = appServlet.addMapping("/*");
}
private WebApplicationContext createWebAppContext() {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(CxfServletConfig.class);
return appContext;
}
}
And my main Spring config looks like this:
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
#Configuration
public class CxfServletConfig {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CxfServletConfig.class);
#Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
return new SpringBus();
}
#Bean
#DependsOn("cxf")
public Server jaxRsServer(ApplicationContext appContext) {
JAXRSServerFactoryBean endpoint = RuntimeDelegate.getInstance().
createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
endpoint.setServiceBeans(Arrays.<Object> asList(testSvc()));
endpoint.setAddress(endpoint.getAddress());
endpoint.setProvider(jsonProvider());
return endpoint.create();
}
#Bean
public Application jaxRsApiApplication() {
return new Application();
}
#Bean
public JacksonJsonProvider jsonProvider() {
return new JacksonJsonProvider();
}
#Bean(name = "testSvc")
public TestService testSvc() {
return new TestService();
}
So just to be clear, the above code is my current, working, deployable configuration. So now I'd like to create a test config that utilizes the same but which also starts Jetty and registers my servlet, and can't quite figure out how. Any help?
Thanks!
EDIT: Turns out I did not need the WebApplicationInitializer at all to get this to work. I ended up creating a Test config for Spring that defines a Jetty server as a bean. Seems to work:
#Configuration
public class TestingSpringConfig {
#Bean (name="jettyServer", destroyMethod = "stop")
public Server jettyServer() throws Exception {
Server server = new Server(0); //start jetty on a random, free port
// Register and map the dispatcher servlet
final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );
final ServletContextHandler context = new ServletContextHandler();
context.setContextPath( "/" );
//fuse uses cxf as base url path for cxf services, so doing so as well here so urls are consistent
context.addServlet( servletHolder, "/mybaseurl/*" );
context.addEventListener( new ContextLoaderListener() );
context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
//this will load the spring config for the CFX servlet
context.setInitParameter( "contextConfigLocation", CxfServletConfig.class.getName() );
server.setHandler( context );
server.start();
//server.join(); if running from a main class instead of bean
return server;
}
#Bean(name = "jettyPort")
#DependsOn("jettyServer")
public Integer jettyPort() throws Exception {
Integer port = jettyServer().getConnectors()[0].getLocalPort();
log.info("Jetty started on port: " + port);
return port;
}
}
i seem to run into a small issue when using #Autowired into a custom cxf interceptor.
My use case is that i want to log soap messages and send these using AMQP to another system. This process works for normal services etc.
But whatever i do, the needed properties do not get autowired and stay null.
I checked the Spring DI log and the context is scanned and pickedup, so what am i missing?
Is this even possible in CXF interceptors?
#Component
public class LogInInterceptor extends AbstractSoapInterceptor {
private #Value("#{rabbitMQProperties['rabbitmq.binding.log.soap']}")
String binding;
#Autowired
AmqpTemplate amqpTemplate;
public LogInInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
logIt(soapMessage);
}
private void logIt(SoapMessage message) throws Fault {
// rest of the code omitted...!!!
amqpTemplate.convertAndSend(binding, buffer.toString());
}
}
You can't mix #InInterceptors (a CXF annotation) and #Component (a Spring annotation). That will create two separate instances of your interceptor: the one whose dependencies are getting injected by Spring, and one created by CXF. (You are providing class names in the #InInterceptors annotation, not a bean ID, so CXF has no way of knowing that you already created an instance in the Spring context.)
Remove the #InInterceptors annotation and, in addition to the component scan:
<context:component-scan base-package="org.example.config"/>
You also need something like this in your application context:
<jaxws:endpoint id="myWebService" address="/MyWebService">
<jaxws:inInterceptors>
<ref bean="myInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
I know this is an old question, but Jonathan W's answer helped me and I would like to add to it.
This is how I got custom interceptors and #Autowired to work with Spring Boot 1.3.1:
http://cxf.apache.org/docs/jax-ws-configuration.html
import java.util.Arrays;
import javax.jws.WebService;
import org.apache.cxf.Bus;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
#Configuration
#EnableAutoConfiguration
#ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class Application extends SpringBootServletInitializer {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private MyInterceptor myInterceptor;
#Autowired
private HelloWorldImpl helloWorldImpl;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
// Replaces the need for web.xml
#Bean
public ServletRegistrationBean servletRegistrationBean(ApplicationContext context) {
return new ServletRegistrationBean(new CXFServlet(), "/api/*");
}
// Replaces cxf-servlet.xml
#Bean
// <jaxws:endpoint id="helloWorld" implementor="demo.spring.service.HelloWorldImpl" address="/HelloWorld"/>
public EndpointImpl helloService() {
Bus bus = (Bus) applicationContext.getBean(Bus.DEFAULT_BUS_ID);
EndpointImpl endpoint = new EndpointImpl(bus, helloWorldImpl);
// Set interceptors here
endpoint.setInInterceptors(Arrays.asList(myInterceptor));
endpoint.publish("/hello");
return endpoint;
}
// Used when deploying to a standalone servlet container, i.e. tomcat
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
// Web service endpoint
#WebService(endpointInterface = "demo.spring.service.HelloWorld")
//#InInterceptors not defined here
public static class HelloWorldImpl {
}
public static class MyInterceptor extends LoggingInInterceptor {
// #Autowired works here
}
}
While working with javascript that uses REST services extensively -- including using vocabs like GET, PUT, POST, DELETES, etc; I have found it hard to mock the server side so front end development can go on independently (of back end).
It is also useful to sometimes capture multi-step data, so we can help reproduce the entire chain of REST even (or bugs related to the front end that are triggered from these chains)
What tools can I use to mock REST calls, esp stateful ones? (i.e. if I do a PUT on some resource, I expect the next GET on it to change somehow)
I tried SOAPUI 4.0.1 and it's REST mocking is disappointing. Plus, my need is beyond single state mocking (which anyone can do with a static .json file). I need to do state transition type of mocks; working with Content-Range headers would be best.
Anyone?
I actually ended up creating my own Java REST Mock Engine that can basically mock any response. As long as you can handcraft or cut-paste a text file that simulates the entire http response, you can use my solution to mock the service.
Here's the servlet:
package com.mockrest.debug;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class MockGridData
*/
public class MockRest extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public MockRest() {
super();
// TODO Auto-generated constructor stub
}
#Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
sub:{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
String setdata = request.getParameter("__setdata");
if (setdata!=null && setdata.length()>0){
System.err.println("Setting Data...");
HttpSession sess = request.getSession(true);
String data = "/"+request.getParameter("__setdata");
sess.setAttribute("data", data);
try{
InputStream is = getServletContext().getResourceAsStream(data);
if (is!=null){
is.close();
response.getWriter().write("Successfully pointed next REST call to:"+data);
}
else{
response.sendError(500, "Cannot find resource:"+data);
}
}
catch (IOException ioe){
response.sendError(500, Arrays.deepToString(ioe.getStackTrace()));
}
}
else{
System.err.println("Fetching Data...");
HttpSession sess = request.getSession(false);
if (sess==null || sess.getAttribute("data")==null){
response.sendError(500,"Session invalid or no Previous Data Set!");
}
String rsrc = (String)sess.getAttribute("data");
System.err.println("Resource Being used:"+rsrc);
InputStream is = getServletContext().getResourceAsStream(rsrc);
if (is!=null){
String statusline = readLine(is);
Pattern statusPat = Pattern.compile("^HTTP/1.1 ([0-9]+) (.*)$");
Matcher m = statusPat.matcher(statusline);
if (m!=null && m.matches()){
int status = Integer.valueOf(m.group(1));
response.setStatus(status, m.group(2));
}
else{
throw new ServletException("Bad input file: status line parsing failed, got this as status line:"+statusline);
}
String line;
Pattern httpHeaderPat = Pattern.compile("^([^:]+): (.*)$");
while ((line=readLine(is))!=null){
if (line.length()==0){
// end of headers
break;
}
Matcher m2 = httpHeaderPat.matcher(line);
if (m2!=null && m2.matches()){
response.setHeader(m2.group(1), m2.group(2));
}
}
OutputStream os = response.getOutputStream();
byte[] buf = new byte[1024];
int size;
while ((size=is.read(buf))>0){
os.write(buf, 0, size);
}
os.flush();
}
}
}
}
private String readLine(InputStream is) throws IOException {
StringBuffer sb = new StringBuffer();
char c;
while ((c=(char)is.read())!='\n'){
sb.append(c);
}
if (sb.charAt(sb.length()-1) == '\r'){
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
}
To configure it, place prebuilt response files inside your WebContent folder. I usually end these files with .http extensions.
An example init.http file is below. Pretend we placed this file inside a folder called data inside WebContent:
HTTP/1.1 200 OK
Date: Wed, 26 Oct 2011 18:31:45 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Content-Range: items 0-1/2
Content-Length: 385
Cache-Control: private
Content-Type: application/json
[
{
"id": "249F0",
"field1": " Global",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
},
{
"id": "962581",
"field2": "Europe",
"displaystartdate": "2007-10-20",
"displayenddate": "2012-10-20",
"status": "Major Delay",
"children": true
}
]
Headers must separate with body by an empty line (no spaces, nada). People familiar with http will notice it's a pure http response. This is on purpose.
You can use this tool to simulate any of the http headers you want the response to have; even going so far to respond with different server header(in my example, I simulated the response pretending to be IIS 6.0); or a different HTTP status code, etc.
To invoke it from your browser/javascript; first prime it with:
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
Then in your javascript or REST AJAX call, if it goes to
http://yourserver/yourweb/MockGridData
with any method or parameter; it will get the http response you previously crafted with; even down to the Content-Range; Cache headers; etc. If you then need the subsequent AJAX call to return something else, simply call with __setdata again. I suggest you setup a few buttons to do the explicit state transition in your web app.
Assuming everything is setup, for a simulated REST chain, a developer may do:
invoke
http://yourserver/yourweb/MockGridData?__setdata=data/init.http
run a javascript module that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
click a button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step1.http
run another javascript step that will result in calling (say, with PUT)
http://yourserver/yourweb/MockGridData
click another button that then does:
http://yourserver/yourweb/MockGridData?__setdata=data/step2.http
run another javascript step that will result in calling (say, with GET)
http://yourserver/yourweb/MockGridData
but this time expecting different result than #4.
This should even work with binary and gzipped responses, but I haven't tested that.
Here is another homegrown rest-mocking tool: https://github.com/mkotsur/restito.
I need to retrieve some information sent in the HTTP headers from within a Web Service. How can I achieve this?
It depends on the language and web service framework you want to use.
Your question title mentions "Servlet Filter" so I assume you work with a Java application container. If your ws framework does not support the of mapping request headers into value objects, you could use a Servlet Filter that processes the header and stores the information somewhere you can retrieve it later. The best option would be to put it in a request attribute. If you can't get to the HttpServletRequest later (which probably makes you ask this question), you can store it into a ThreadLocal variable, but this is trickier.
I'll give you a minimal example:
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class Filter implements javax.servlet.Filter {
public ThreadLocal<String> local;
#Override
public void doFilter(ServletRequest req, ServletResponse response,
FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
String bar = request.getHeader("foo");
local.set(bar);
// you can now retrieve the header value in your code with Filter.local.get()
try {
chain.doFilter(request, response);
} finally {
local.remove(); // clean up
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
local = new ThreadLocal<String>();
}
}
It works, but in a real life implementation you should store an Object of your own Class in the ThreadLocal (e.g. a Bean) instead of a mere String. You should consider putting the ThreadLocal variable outside your Filter (e.g. as a static variable somewhere in a more logical place).