This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
Summary: | improvement to template for web service clients | ||
---|---|---|---|
Product: | webservices | Reporter: | pbelbin <pbelbin> |
Component: | Code | Assignee: | Milan Kuchtiak <mkuchtiak> |
Status: | NEW --- | ||
Severity: | blocker | ||
Priority: | P2 | ||
Version: | 6.x | ||
Hardware: | All | ||
OS: | All | ||
Issue Type: | ENHANCEMENT | Exception Reporter: |
Description
pbelbin
2009-05-15 00:00:24 UTC
Thank You. Good idea. You've meant the runtime location of wsdl file, not the service right ? (the service url information is in wsdl) Another solution would be to use the JAX-WS feature (javax.xml.ws.BindingProvider class): Sample code snippet: YourService service = new YourService(); YourServicePort port = service.getYourServicePort(); // You can change the runtime location of wsdl file by using the following code: /* javax.xml.ws.BindingProvider binding = (javax.xml.ws.BindingProvider)port; binding.getRequestContext().put( javax.xml.ws.BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://test.webservice.com/service/MyService?wsdl"); */ Would this solution work for you ? Note: in objects initialized by J2EE container (e.g. in servlets) we already (since Netbeans 6.0) generate @WebServiceRef annotation for service field: @WebServiceRef(wsdlLocation = "http://test.webservice.com/service/MyService?wsdl") YourService service; I'm NOT talking about the location of the WSDL. I'm talking about where the WSDL is pointing - where the code is going to try to connect to. I think we're on a similar page, but there is a problem with your code.... here is what I'm trying to prevent: a) developer points the ide to a development server (ie: not localhost) to use a web service by pointing at the WSDL using a URL on some other machine. b) ide stores the wsdl locally along with the URI that points to the development server, and generates proxy code (***that has a static copy of the URL pointing to the development server hosting the web service***). c) the code gets deployed to a production server. d) what happens when the default constructor is used for the service proxy? it tries to open a connection with the development server. this is a time-wasting no-no. the production client should not even attempt this. ok, so I think we both understand the problem, however: the code I've provided avoids this from happening because it changes the URL *before* the constructor tries to open a connection to the web service. Your code example does not do this. in the code you give, we use the default constructor and method to get the service port, and then try to update the URI after having obtained the port object: YourService service = new YourService(); YourServicePort port = service.getYourServicePort(); the problem is that after having used the above to lines of code, regardless of what you do afterwards, the client has already tried to access the web service that was defined in the WSDL - because the URI is statically built into the proxy code. take a look at the proxy code, and you'll see exactly what I'm talking about. the default constructor uses the statically defined URI that was taken from the WSDL that was used during development. unfortunately, the designers of the jax-ws api standard didn't think it would be good to provide a constructor variant where we could just pass a parameter to alter the way the initial default URI/URL is defined. what would be great would be a way for the glassfish container to be configured to point to UDDI servers that could then dynamically resolve the question of what the URI should be. however, it seems that UDDI servers have fallen out of favour (possibly due to them being yet another layer of abstraction that many don't want to have to deal with). If UDDI support was more up front in the IDE, this would likely change. does this help? *that's why my code is the way it is*: it obtains the QName from the proxy, and creates a new URL, and uses the non- default constructor for the service. in this way, the statically defined default URI for the web service is *never used*. I suppose, a way of achieving a default would be this: import javax.xml.namespace.QName; import javax.xml.ws.WebServiceClient; WebServiceClient ann = YourService.class.getAnnotation(WebServiceClient.class); URL url = new URL(ann.wsdlLocation()); QName qname = new QName(ann.targetNamespace(), ann.name()); YourService service = new YourService(url,qname); YourPort binding = service.getYourPort(); the above gives exactly what you have today - use of the default URL (taken from the WSDL via the annotation), but, it's very easy to see where this can be changed to make it use any service URL instead of the one that's been hard coded into the proxy. Yes, may me the solution found by you is faster. I haven't tested that. Nevertheless, in Netbeans 6.7 the jax-ws-catalog.xml was implemented (in all project types), and, this means IMHO, the code below shouldn't try to open the connection with the development server (as you wrote), since all wsdl resources are mapped to local resources (located under WEB-INF/wsdl) now. YourService service = new YourService(); YourServicePort port = service.getYourServicePort(); Another point: We need to distinguish between the URL of wsdl file and URL of the web service : The 2 lines above are not opening connection with the web service, but with wsdl file. Only the code related to calling WS operation (on proxy object) is connecting actually to the web service. As far as jax-ws-catalog.xml, the priorities they are following. - JAX-WS code is trying to access wsdl file that is mapped to original wsdl url in jax-ws-catalog.xml - if not found JAX-WS is looking for originall wsdl location (referenced in service class) ok, if that's true, then, why does the blogger here http://netbeans.dzone.com/articles/portability-and-performance think he needs to make the manual changes he suggests? I see no point in having to make these manual changes. we should be able to have the default template provide very good code that makes the manual messing around a non-issue so that it can be done in code if needed. please advise. regards, peter. The manual changes the writer is talking about just depict the functionality of jax-ws-catalog.xml. They don't need to be done. Your solution is really interesting and straightforward. We should really I am going implement it, but simplify to (example): ===== QName qname = new QName("http://www.webserviceX.NET/", "CurrencyConvertor"); CurrencyConvertor service = new CurrencyConvertor(new URL("http://www.webservicex.net/CurrencyConvertor.asmx?wsdl"),qname); CurrencyConvertorSoap port = service.getCurrencyConvertorSoap(); ===== Note: 3 string literals are used there instead of getAnnotation method. IDE should be able to resolve these strings from generated java source file (YourService.java). Thank you for appreciating that I want to improve things. There is however, an issue with the solution that you propose. The issue is that the values that you are expecting the template usage processing to insert into the developer's code will become hard coded into the source code. If (as often happens) something changes in the design of the WSDL for the web service, simply re generating the client proxy code will now introduce an update dependancy that could require many pieces of code to have to be visited to bring it into alignment. I am keen to have the solution not become yet another thing that needs to be maintained if such a change happens, as there are already enough scenarios that would require manual changes to allow code to work after a change of some sort. ie: the QName values that you're anticipating... Using my solution takes the values that were available at the time the proxy code was generated, so it's always going to be in sync with the proxy code, and should not have to be revisited due to web service QName variations. please re-consider using the code I supplied. best regards, peter. I see your point. On the other hand in case of hard strings the readability of the code is better. With no hard strings the client code is a little bit more flexible, but after some changes (e.g. when service name is changed, the client code isn't compilable anyway. What about the hard coded string used in service constructor : CurrencyConvertor service = new CurrencyConvertor(new URL("http://www.webservicex.net/CurrencyConvertor.asmx?wsdl"),qname); vs. CurrencyConvertor service = new CurrencyConvertor(new URL(ann.wsdlLocation()),qname); I supposed you wanted to have ability to change it simply in the client code. If I correctly understand the main goal of this change is avoiding the usage of the URL string created in static code block, that is contained in generated class, annotated with @WebServiceClient. The static block will be called in any case (when the class is loaded by class loader). We can only avoid usage of that URL. I'll consult the stuff with JAX-WS guys. The usage of javax.xml.ws.BindingProvider together with jax-ws-catalog.xml looks also flexible enough. I think that your suggestion of CurrencyConvertor service = new CurrencyConvertor(new URL(ann.wsdlLocation()),qname); would work well, resulting in something like: -------------------------------------------------------------------------------- import javax.xml.namespace.QName; import javax.xml.ws.WebServiceClient; WebServiceClient ann = YourService.class.getAnnotation(WebServiceClient.class); QName qname = new QName(ann.targetNamespace(), ann.name()); YourService service = new YourService(new URL(ann.wsdlLocation()),qname); YourPort binding = service.getYourPort(); -------------------------------------------------------------------------------- with no hard strings in the generated code. the thing I am really wanting to avoid is hard coding any strings in the client code, while still making it easy to see where to update the URL for the live web service at runtime. it would be absolutely wonderful if the URL's could actually say something like "uddi:serviceName" and have the jax-ws use jax-r to ask the container about the uddi server and find the details itself. any chance of asking about that when you talk with the jax-ws people? |