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.
Related
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.
I create a context and assign as tomcat context with urlpattern /api.
Now, I add DefaultServlet to Tomcat and create a filter and map for jersey resourceConfig.
Context context = tomcat.addContext("/api", base.getAbsolutePath());
Tomcat.addServlet(context, "default", new DefaultServlet());
context.addServletMapping("/*", "default");
final FilterDef def = new FilterDef();
final FilterMap map = new FilterMap();
def.setFilterName("jerseyFilter");
def.setFilter(getJerseyFilter());
context.addFilterDef(def);
map.setFilterName("jerseyFilter");
map.addURLPattern("/*");
context.addFilterMap(map);
tomcat.start();
private static Filter getJerseyFilter(){
final ResourceConfig config = new ResourceConfig()
.packages(Main.class.getPackage().getName())
// create instance of Resource and dynamically configure to ResourceConfig
.register(new Resource(new Core(), configuration))
.register(JspMvcFeature.class) // register jspMVC
.property(ServletProperties.FILTER_FORWARD_ON_404, true);
return new ServletContainer(config);
}
Now, I am successfully able to access localhost:PORT/api/<end_point>
Now my question is, I want to assign a path /serve/* in ServletMapping like
Tomcat.addServlet(context, "default", new DefaultServlet());
context.addServletMapping("/serve/*", "default");
Then I want to access the resource on localhost:PORT/api/serve/<end_point>
but it prompt error
HTTP Status 404 -
type Status report
message
description The requested resource is not available.
Apache Tomcat/8.0.26
I build a simple Jersey rest server, that handle a simple service.
In main class that start the server, i read properties file that i want to
provide/pass to jax handler classes.
The server works, i just have to make a way to share config parameters of
main class with handler of requests.
How i can do this ?
The code of main, where i read de properties file one time only:
...
public HashMap resources;
// this start the listener jersey server...
String host="http://localhost/";
int port = 9998;
URI baseUri = UriBuilder.fromUri(host).port(port).build();
ResourceConfig config = new ResourceConfig();
config.packages(true, "br.com.myserver");
config.register(MyHandler.class);
// I WANT TO ACCESS/SHARE THIS WITH THE HANDLER -> MyHandler.class
resources.put("host_user","bla bla bla");
HttpServer server = JdkHttpServerFactory.createHttpServer(baseUri, config);
System.out.println("--Press Enter to STOP the server--");
System.in.read();
Server.stop(0);
System.out.println("Server stoped!");
...
The code of MyHandler, where i want to access main properties:
#Path("myapp")
public class MyHandler
{
#POST #Path("/testep")
#Consumes("application/json")
#Produces("text/plain")
public String action1(#Context Request request, String json)
{
// HERE I WANT TO ACCESS THE RESOUCES HASHMAP OF MAIN HERE
// (how get main handler here).resources.get("host_user");
// maybe access main class, or something like
// the intention is to avoid the read of config at all requests here
System.out.println("received event:" + json);
return "event received " + json;
}
}
Any ideas will be apreciated, thanks.
Any properties you configure the ResourceConfig using it's property(key, value), will be accessible through the Configuration interface which you can inject into your resource class.
ResourceConfig config = new ResourceConfig();
config.property("host_user","bla bla bla");
...
#Path("myapp")
public class MyHandler
{
#Context
Configuration configuration;
public String action1(#Context Request request, String json) {
Map<String, Object> props = configuration.getProperties();
}
}
See Also:
Configuration Properties with Jersey for some other ideas.
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.
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();
}
}