How to specify wsdlLocation for local file - java

I am new to the game of web-service clients, and have generated code using the wsdl2java maven dependency.
I am packaging this project as a .war file.
My issue is that I do not know how to make the autogenerated client reach an endpoint across domains, and I also do not know how to set the client's wsdlLocation properly.
Starting with the latter:
Inside of the autogenerated service class, I found a static URL WSDL_LOCATION attribute, as well as 'parameters?' to a WebServiceClient annotation.
#WebServiceClient(name = "my_service",
wsdlLocation = "file:/c:/tmp/my_service.wsdl",
targetNamespace = "someAutoGenTargetNS/wsdl")
public class my_service_Service extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("someAutoGenTargetNS/wsdl", "my_service");
public final static QName my_service = new QName("http://someAtuoGenTargetNS/wsdl", "my_service");
static {
URL url = null;
try {
url = new URL("file:/c:/tmp/my_service.wsdl");
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger(my_service_Service.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "file:/c:/tmp/my_service.wsdl");
}
WSDL_LOCATION = url;
}
Currently, the WSDL_LOCATION url is always set to null, as it can not find the filepath specified (which is expected). I have the wsdl and xsd stored in the resources folder, but do not know how to specify the path to reach that. I have tried
new URL("file:/resources/my_service.wsdl")
new URL("file:/src/main/java/resources/my_service.wsdl")
new URL("classpath:my_service.wsdl")
and quite a few others. What is the correct way to do this, and if it requires an xml-catalog, where can I find documentation about where to put the catalog.xml file.
And now the former:
I believe my implementation to change the endpoint to the location I want is correct, and it is the wsdlLocation issue that is giving me a headache. Here is my implementation to change the endpoints. If this does not look right, simply point me in the direction of what to use, no need for a full implementation.
private static final QName SERVICE_NAME = new QName(""someAutoGenTargetNS/wsdl"", "my_service");
private URL wsdlURL = my_service_Service.WSDL_LOCATION;
my_service_Service ss;
my_service port;
public my_service_client()
{
//Redacted code for trusting all SSL Certs and hostnameVerifiers as it is not needed for the scope of this question
this.ss = new my_service_Service(this.wsdlURL,SERVICE_NAME);
this.port = ss.getMy_Service();
BindingProvider bp = (BindingProvider) this.port;
Map<String,Object> clientRequestContext = bp.getRequestContext();
clientRequestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://New_Endpoint_IP");
//Basic auth header credentials
clientRequestContext.put(BindingProvider.USERNAME_PROPERTY,"username");
clientRequestContext.put(BindingProvider.PASSWORD_PROPERTY,"password");
}
Resources I attempted to understand prior to asking this question:
1
2
3
4
5
6
7+
8
Conclusively, I am coming to the realization I would much rather work with HTTP than SOAP, but legacy systems require legacy interaction.
Error's received that lead me to believe this is a wsdlURL issue:
javax.xml.ws.soap.SOAPFaultException: Internal Error (from client)
org.apache.cxf.binding.soap.SoapFault: Internal Error (from client)

Figured out the issue (4 days of tracking the problem later, and i can solve it shortly after asking the question here...)
This is indeed a valid way of setting the endpoint URL. That answers that question.
I adopted the classLoader.getResource approach from this reference to set the wsdlLocation
My new code became:
#WebServiceClient(name = "my_service",
wsdlLocation = "classpath:my_service.wsdl",
targetNamespace = "someAutoGenTargetNS/wsdl")
public class my_service_Service extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("someAutoGenTargetNS/wsdl", "my_service");
public final static QName my_service = new QName("http://someAtuoGenTargetNS/wsdl", "my_service");
static {
URL url = null;
url = my_service.class.getClassLoader().getResource("my_service.wsdl");
WSDL_LOCATION = url;
}
Lastly I realized that the most basic web-service call I was trying to utilize was incorrectly setting the request body. I had set the request_body to null, in stead of instantiation a new instance of the request class that was autogenerated. This is what was throwing these two errors, but I am sure fixing the above helped lead me to the solution by enforcing my understanding of how these pieces work together.

Related

Jersey +Grizzly - #ApplicationPath ignored

I'm running Jersey 2.26-b09 on top of Grizzly, and I'm using the following code to start the Grizzly HTTP server:
public void start() {
URI uri = UriBuilder.fromPath("").scheme("http").host("localhost").port(8084).path("/rest").build();
Map<String, String> params = new HashMap<>(16);
String applicationClassName = RestApplication.class.getName();
String applicationPackageName = RestApplication.class.getPackage().getName();
String productionPackageName = ProductionService.class.getPackage().getName();
params.put(ServletProperties.JAXRS_APPLICATION_CLASS, applicationClassName);
params.put(ServerProperties.PROVIDER_PACKAGES, productionPackageName + "," + applicationPackageName);
HttpServer server = GrizzlyWebContainerFactory.create(uri, params);
server.start();
}
The RestApplication class extends Application, and has a #ApplicationPath("/system") annotation.
The ProductionService class is a REST resource with a #Path("/production") annotation.
I can see that the path specified in the #ApplicationPath is ignored: my resources can be accessed at /rest/production and not at /rest/system/production.
I've tried to change the URI to /rest/system instead of /rest, but to no avail:
URI uri = UriBuilder.fromPath("").scheme("http").host("localhost").port(8084).path("/rest/system").build();
The application is deployed in the root context /rest, not /rest/system.
What am I missing?
Of course as a workaround I could change the resource path from "/production" to "/system/production", but I would like to know why the application path is ignored.
I've changed the code that creates and initializes the server to:
public void start() {
URI uri = UriBuilder.fromPath("").scheme("http").host("localhost").port(8084).build();
Map<String, String> params = new HashMap<>(16);
String applicationPackageName = RestApplication.class.getPackage().getName();
String productionPackageName = ProductionService.class.getPackage().getName();
params.put(ServerProperties.PROVIDER_PACKAGES, productionPackageName + "," + applicationPackageName);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri);
WebappContext context = new WebappContext("system", "/rest/system");
ServletRegistration registration = context.addServlet("jersey", ServletContainer.class);
registration.setInitParameters(params);
registration.addMapping("/*");
context.deploy(server);
server.start();
}
A Web Application context is created and serves the resources at the desired path. Since the servlet container initializer is not invoked in this programmatic approach, the ServletProperties.JAXRS_APPLICATION_CLASS property is not set.
I thought that setting this property were doing the job, but it does not. Thanks to #peeskillet for the hint.

What are the methods testing POST to prevent status=405?

I was trying to build a RESTful web service using Jersey.
In my server side code, there is a path with name "domain" which I use to display content. The content of the page the "domain" refers to is accessible only correct username and password are input.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("domain")
public ArrayList<String> domainList(#Context HttpServletRequest req) throws Exception{
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername((String) req.getSession().getAttribute("username"));
//Set username from input, HTML form
profile.setPassword((String) req.getSession().getAttribute("password"));
//Set password from input, HTML form
try (ALMConnection connection = new ALMConnection(profile);) {
if (connection.getOtaConnector().connected()) {
Multimap<String, String> domain = connection.getDomains();
ArrayList<String> domain_names = new ArrayList<String>();
for(String key : domain.keys()){
if(domain_names.contains(key)) domain_names.add(key);
}
return domain_names; //return the content
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
When I attempted to test if correct content was returned, I got an error (status=405, reason=Method Not Allowed). Below is my client side test.
public static void main(String[] args){
Environments environments = new DefaultConfigurationBuilder().build();
final ALMProfile profile = new ALMProfile();
profile.setUrl(environments.getAutomation().getAlmProfile().getUrl());
profile.setUsername("username"); //Creating a profile with username and password
profile.setPassword("password");
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target(getBaseURI());
String response = target.path("domain").request().accept
(MediaType.APPLICATION_JSON).get(Response.class).toString();
//Above is the GET method I see from an example,
//probably is the reason why 405 error comes from.
System.out.println(response);
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/qa-automation-console").build();
}
The servlet configuration is good. We have other paths succesfully running.
I suspect the reason might come from I used a GET method to do the job that is supposed to be POST.
But I am not familiar to Jersey methods I can use.
Does anyone know any methods that I can use to test the functionality?
See 405 Status Code
405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.
Your endpoint is for a #POST request. In your client you are trying to get().
See the Client API documentation for information on how to make a POST request. If it is supposed to be a GET request, then simply change the method annotation to #GET.
Also note, for your #POST resource methods, you should always put a #Consumes annotation with the media types the method supports. If the client send a media type not supported, then they will get a 415 not supported as expected. I would have posted an example of the client post, but I have no idea what type are you are expecting because of the missing annotation, also you don't even have a post object as a method parameter so I am not even sure if your method is really even supposed to be for POST.
See Also:
How to send json object from REST client using javax.ws.rs.client.WebTarget

Does anyone encounter unuseful rootpath in resteasy

I'm using RESTEasy to write a example of WebService, and set the root resource path.But I find that even no root path in the url, I still can get the right resource.
Main function Code:
NettyJaxrsServer netty = new NettyJaxrsServer();
ResteasyDeployment deploy = new ResteasyDeployment();
List<Object> resources = new ArrayList<Object>();
resources.add(new UserService());
deploy.setResources(resources);
netty.setDeployment(deploy);
netty.setPort(8180);
netty.setRootResourcePath("/hello/");
netty.setSecurityDomain(null);
netty.start();
Service Code:
#Path("user")
#Produces(MediaType.APPLICATION_JSON)
public class UserService {
For the code, url /user can work normal, no need to add root path of /hello. I checked the source code; it adds the root path by itself.
source code:
public static String getEncodedPathInfo(String path, String contextPath)
{
if(contextPath != null && !"".equals(contextPath) && path.startsWith(contextPath))
path = path.substring(contextPath.length());
return path;
}
My question is why RESTEasy do this? I can't understand.

Reference to own wsdl url

I'm building a web service that's supposed to register on another server by sending its wsdl URL to that server.
I built a very basic web service in Netbeans,
#WebService
public class RegisterTest{
#WebMethod(operationName = "emphasize")
public String emphasize(#WebParam(name = "inputStr") String input){
return input + "!!!";
}
}
and Netbeans automatically directs me to localhost:8080/RegisterTest/RegisterTestService?Tester, and naturally, the wsdl can be found at localhost:8080/RegisterTest/RegisterTestService?wsdl.
How would I programmatically get this URL?
Edit:
I've noticed that the only place that seems to store this URL is the glassfish server itself. The context-root seems to only be found in glassfish/domain//config/domain.xml.
Is there a nice way of accessing the glassfish server APIs? I can easily get the endpoint address through the UI in applications > serviceName > View Endpoint, is there a programmatic way of doing this?
I've tried looking through asadmin commands, but can't seem to find anything there that gets the context-root or the endpoint URL either.
Untested, but should be pretty close to what you're looking for:
#WebService
public class RegisterTest
{
#Resource
private WebServiceContext context;
#WebMethod(operationName = "emphasize")
public String emphasize(#WebParam(name = "inputStr") String input)
{
return input + "!!!";
}
#WebMethod(operationName = "getWsdlUrl")
public String getWsdlUrl()
{
final ServletContext sContext = (ServletContext)
this.context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
final HttpServletRequest req = (HttpServletRequest)
this.context.getMessageContext().get(MessageContext.SERVLET_REQUEST);
final StringBuilder sb = new StringBuilder();
sb.append(req.isSecure() ? "https" : "http");
sb.append("://");
sb.append(req.getLocalName());
if ((req.isSecure() && req.getLocalPort() != 443) ||
(!req.isSecure() && req.getLocalPort() != 80))
{
sb.append(":");
sb.append(req.getLocalPort());
}
sb.append(sContext.getContextPath());
sb.append(RegisterTest.class.getSimpleName());
sb.append("Service?wsdl");
return sb.toString();
}
}

Retrieve a list of entities from a Restfull service (inside client app)

Im new to Rest web services and say Ive created this web service using Netbeans
#Path("browse")
#Stateless
public class ArticleBrowseResource {
#EJB
private ArticleSearcherLocal ejbRef;
#GET
#Produces(MediaType.APPLICATION_XML)
public List<Article> browse(#DefaultValue("") #QueryParam("username") String username,#QueryParam("sd") String sd) {
// convert sd string to date
List<Article> articles = ejbRef.search(username, date);
return articles;
}
}
where Article is an entity which is anotated with #XmlRootElement
Now how am I supossed to retreive this list of articles in my client which for simplicity lets just say it is a java standard application? In SOAP web services I know that these objects are automatically generated but not in Rest.
This is the client class generated for this service by Netbeans
public class ArticleBrowseClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "http://localhost:8080/cityblog/rest";
public ArticleBrowseClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
client = Client.create(config);
webResource = client.resource(BASE_URI).path("browse");
}
public <T> T browse(Class<T> responseType, String username, String sd) throws UniformInterfaceException {
WebResource resource = webResource;
if (username != null) {
resource = resource.queryParam("username", username);
}
if (sd != null) {
resource = resource.queryParam("sd", sd);
}
return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public void close() {
client.destroy();
}
}
What is the best and simplest way to resolve this issue?
Any help is appreciated and
thx in advance
Please try fewer code generation and more understanding of what you are actually doing. On the server, you generate a XML message with help of JAXB. On the client side, you can consume this XML with a programming language and library you like. Just use tools like curl to see what is going actually over "the wire". Your generated client site looks fully reasonable. You just need your Article class from the server side on the client side. The generated code uses Jersey which can read XML messages per JAXB per default. So just drop your server side Article class in your client side classpath and use it. But please also have a look at the wire level protocol to understand the portability of your REST API.

Categories

Resources