Surprised to see nobody out there has run into this before.
Anyway, I've figured out a solution. It might not be the best way, let
the developers figure that much out.
Here's what I did.
First, org.codehaus.xfire.transport.http.XFireServletTransport is where
the wsdlsoap:address is composed. It simply takes the base URL from the
incoming request. Since in my case mod_proxy in apache is redirecting
the users original request this doesn't work thee way I needed it to.
So I wrote my own transport class extending
org.codehaus.xfire.transport.http.SoapHttpTransport, the same class that
XFireServletTransport extends. My class is Spring friendly and has a
wsdlServiceURL property and setter.
Next, simply registering this transport with the TransportManager isn't
enough, although it probably should be. The constructor in
org.codehaus.xfire.transport.http.XFireServletController actually
unregisters the original SOAP Transport and replaces it with an
instatnce of XFireServletTransport. This makes the Spring configuration
of the TransportManager somewhat useless. So, I had to write my own
controller extending XFireServletController. Mine does not replace the
original transport in the contructor, rather I chose to do this in the
setter for the wsdlServiceURL property. I actually have the value I
need defined as a JNDI variable in Tomcat and use Spring to set this
property on the controller. The controller in turn passes it along to
my transport and then registers my transport with the TranportManager.
The next step was to write new servlet class. The existing
org.codehaus.xfire.spring.XFireSpringServlet seems kind wierd to me. It
seems to know that an instance of XFire is wired in by Spring and looks
it up from the ApplicationContext. However, it doesn't do the same for
the controller, which is also wired in already by Spring. So, my
efforts to create a new controller and modify its Spring configuration
had no effect. My servlet class extends
org.codehaus.xfire.transport.http.XFireServlet, the same class that the
original XFireSpringServlet extends. Mine overrides the
createController() method to simply return the one I already have from
Spring instead of letting Super create a new one. I extended the init()
method to lookup the controller from the Spring ApplicationContext.
Lastly, I had to modify some configuration files. The
org.codehaus.xfire.spring.xfire.xml file where the controller was
originally wired need to be changed. I copied this into my project and
made the necessary changes. I also changed my web.xml to use my servlet
class instead of XFireSpringServlet. I also had to modify my Tomcat
server.xml file to define the new JNDI variable.
That's it. I can now deploy my application from my desktop, to dev, to
uat, to production and the URL in my wsdls are correct in each
environment without the need to make any post deployment changes or
maintain a static wsdl files in each environment. Schweet! I have 6
services each proving dozens of methods. Maintining 6 wsdl files in 4
environments just wasn't a solution I was happy with.
Some of you might be asking why was all this trouble necessary. Well,
here's the skinny. We have a Flex application that accesses my
services. It runs on users desktops so it needs my services exposed to
the internet. All access from the users has to access Apache on port
443 using https. Apache in turn uses mod_proxy to pass valid requests
on to Tomcat (on the same or different server) using http on port 8080.
So the incoming request that XFireServletTransport sees is
http://tomcatServer:8080/... and that is what was getting set in the
wsdl. When the Flex app. tries to invoke a service using that address,
its not visible to the internet. Boom.
I hope this helps someone else as this did take some time to figure out,
code, and test. Let me know if you find this helpful.
My code:
public class *MwcSoapHttpTransport* extends SoapHttpTransport {
*protected String baseURL;*
protected Channel createNewChannel(String uri) {
XFireServletChannel c = new XFireServletChannel(uri, this);
c.setEndpoint(new DefaultEndpoint());
return c;
}
*public String getServiceURL(Service service) {
HttpServletRequest req = XFireServletController.getRequest();
if (req == null) return super.getServiceURL(service);
StringBuffer output = new StringBuffer( 128 );
output.append( getBaseURL() );
output.append( req.getRequestURI() );
return output.toString();*
}
public String getBaseURL() {
return baseURL;
}
public void setBaseURL(String baseURL) {
this.baseURL = baseURL;
}
}
----------------------------------------------------------------------------------------------------------------------
public class *MwcXFireServletController* extends *XFireServletController* {
private String wsdlServiceURL;
public MwcXFireServletController(XFire xfire, ServletContext
servletContext) {
super(xfire,servletContext);
this.xfire = xfire;
this.servletContext = servletContext;
}
public String getWsdlServiceURL() {
return wsdlServiceURL;
}
public void *setWsdlServiceURL*(String wsdlServiceURL) {
this.wsdlServiceURL = wsdlServiceURL;
// Create a SOAP Http transport with all the servlet addons
*MwcSoapHttpTransport* transport = new *MwcSoapHttpTransport()*;
*transport.setBaseURL(this.wsdlServiceURL);*
transport.addFaultHandler(new FaultResponseCodeHandler());
Transport oldSoap =
getTransportManager().getTransport(SoapHttpTransport.SOAP11_HTTP_BINDING);
if (oldSoap != null) getTransportManager().unregister(oldSoap);
getTransportManager().register(transport);
}
}
----------------------------------------------------------------------------------------------------------------------
public class *MwcXFireSpringServlet* extends XFireServlet {
private String xfireBeanName = "xfire";
*private String controllerBeanName = "xfire.servletController";*
public void init(ServletConfig servletConfig) throws ServletException {
ApplicationContext appContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(servletConfig.getServletContext());
String configBeanName =
servletConfig.getInitParameter("XFireBeanName");
xfireBeanName = ((configBeanName != null) &&
(!"".equals(configBeanName.trim()))) ? configBeanName
: xfireBeanName;
xfire = (XFire) appContext.getBean(xfireBeanName, XFire.class);
super.init(servletConfig);
*controller = (MwcXFireServletController)
appContext.getBean(controllerBeanName, MwcXFireServletController.class);*
}
public XFire createXFire() {
return xfire;
}
*public XFireServletController createController() throws
ServletException {
return controller;
}*
}
======================================================================
<bean id="xfire.servletController"
class="*com.mwc.util.MwcXFireServletController*"
singleton="true">
<constructor-arg index="0"><ref bean="xfire" /></constructor-arg>
<constructor-arg index="1"><null></null></constructor-arg>
*<property name="wsdlServiceURL">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property
name="jndiName"><value>java:comp/env/prop/wsdlServiceURL</value></property>
</bean>
</property>*
</bean>
---------------------------------------------------------------------------------------------------------------------
web.xml
<servlet>
<servlet-name>SOAPServlet</servlet-name>
<servlet-class>*com.mwc.util.MwcXFireSpringServlet*</servlet-class>
</servlet>
Jack
Jack Schwenderman wrote:
I am using Spring and XFire to configure and expose my services.
I run my service application on Tomcat behind a firewall. Apache
HTTPD is exposed through the firewall so all access to all services
pass through Apache on port 80.
The problem I have is that the auto-generated WSDL contains the port
of the Tomcat server as follows:
<wsdlsoap:address
location="http://*tomcatserver:8080*/MyService/xfire/InventoryService"/>
and I need it to be the Apache port instead like this:
<wsdlsoap:address
location="http://*apacheserver*/MyService/xfire/InventoryService"/>
I've been all over the docs on xfire.codehaus.org including the
Users Guide and Articles and I've been reading the mailing list
archives as well with no real progress. I'm hoping someone else has
already tackled this issue as I think it should be fairly common. Any
help would be greatly appreciated!
Thanks,
Jack
PS. For me the Search feature on the Archive page doesn't work so it's
a tough task to browse through the archives. I get the following
error from the server:
Application error
Change this error message for exceptions thrown outside of an action
(like in Dispatcher setups or broken Ruby code) in public/500.html
I just found that Search does work via Gmane however. Other than
serving up a static wsdl file, I haven't really found a good
solution. I'd rather not serve up a static wsdl as it defeats the
purpose of auto-generating.