/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.jboss.soa.esb.actions.soap.adapter.cxf;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import javax.wsdl.Definition;
import javax.wsdl.WSDLException;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.wsdl.xml.WSDLWriter;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.endpoint.ServerRegistry;
import org.apache.cxf.resource.ResourceManager;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.wsdl.WSDLManager;
import org.apache.cxf.wsdl11.ServiceWSDLBuilder;
import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.util.JBossDeployerUtil;
import org.jboss.soa.esb.actions.soap.WebServiceUtils;
import org.jboss.soa.esb.actions.soap.adapter.JBossWSFactory;
import org.jboss.soa.esb.actions.soap.adapter.SOAPProcessorFactory;
import org.jboss.soa.esb.util.ClassUtil;
import org.jboss.wsf.spi.deployment.Endpoint;
import org.jboss.wsf.stack.cxf.configuration.BusHolder;
/**
* Factory for JBossWS CXF specific details.
*
* @author <a href="mailto:kevin.conner@jboss.com">Kevin Conner</a>
*/
public class CXFFactory extends JBossWSFactory
{
/**
* The SOAP Processor factory.
*/
private final SOAPProcessorFactory soapProcessorFactory = new JBossWSCXFFactory() ;
/**
* The factory for accessing the Bus.
*/
private static final BusFactory BUS_FACTORY ;
/**
* The Logger for this class.
*/
private static final Logger LOGGER = Logger.getLogger(CXFFactory.class) ;
@Override
public SOAPProcessorFactory getSOAPProcessorFactory()
{
return soapProcessorFactory ;
}
@Override
public String getWsdlLocation(final Endpoint endpoint, final String endpointName)
{
final ClassLoader old = Thread.currentThread().getContextClassLoader();
try
{
initialiseContextClassLoader(endpoint);
final Definition definition = getDefinition(endpoint) ;
if (definition != null)
{
final String documentBaseURI = definition.getDocumentBaseURI() ;
try
{
final String result ;
if (documentBaseURI == null)
{
result = new URI(ESB_INTERNAL_URI, endpointName, null).toString() ;
}
else if (documentBaseURI.startsWith("jndi"))
{
final URI resourceURI = URI.create(documentBaseURI) ;
final URI endpointURI = URI.create(endpoint.getAddress()) ;
final String resourcePath = resourceURI.getPath() ;
final String endpointPath = endpointURI.getPath() ;
final String urlPattern = endpoint.getURLPattern() ;
final int urlPatternStart = endpointPath.lastIndexOf(urlPattern) ;
final String prefix = (urlPatternStart >= 0 ? endpointPath.substring(0, urlPatternStart) : endpointPath) ;
final int prefixStart = resourcePath.indexOf(prefix, 1) ;
final String fragment = (prefixStart >= 0 ? resourcePath.substring(prefixStart + prefix.length()) : resourcePath) ;
result = new URI(ESB_INTERNAL_URI, endpointName, fragment).toString();
}
else
{
result = documentBaseURI ;
}
return result ;
}
catch (final URISyntaxException urise)
{
throw new IllegalArgumentException("Could not create internal URI reference for endpoint " + endpointName, urise) ;
}
}
return null ;
}
finally
{
Thread.currentThread().setContextClassLoader(old);
}
}
@Override
public InputStream getWsdl(final String uri)
throws IOException
{
final URI endpointURI ;
try
{
endpointURI = new URI(uri) ;
}
catch (final URISyntaxException urise)
{
final IOException ioe = new IOException("Failed to parse endpoint URI") ;
ioe.initCause(urise) ;
throw ioe ;
}
final String endpointName = endpointURI.getSchemeSpecificPart() ;
final Endpoint endpoint = WebServiceUtils.getDeploymentEndpoint(endpointName) ;
final ClassLoader old = Thread.currentThread().getContextClassLoader();
try
{
initialiseContextClassLoader(endpoint);
final String fragment = endpointURI.getFragment() ;
if (fragment != null)
{
final Bus bus = BUS_FACTORY.getBus(endpoint) ;
final ResourceManager resourceManager = bus.getExtension(ResourceManager.class) ;
return resourceManager.getResourceAsStream(fragment) ;
}
else
{
final Definition definition = getDefinition(endpoint) ;
if (definition != null)
{
final Bus bus = BUS_FACTORY.getBus(endpoint) ;
final WSDLManager wsdlManager = bus.getExtension(WSDLManager.class) ;
final WSDLWriter wsdlWriter = wsdlManager.getWSDLFactory().newWSDLWriter();
definition.setExtensionRegistry(wsdlManager.getExtensionRegistry());
final ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
try
{
wsdlWriter.writeWSDL(definition, baos);
}
catch (final WSDLException wsdle)
{
final IOException ioe = new IOException("Failed to generate WSDL") ;
ioe.initCause(wsdle) ;
throw ioe ;
}
return new ByteArrayInputStream(baos.toByteArray()) ;
}
}
return null ;
}
finally
{
Thread.currentThread().setContextClassLoader(old);
}
}
@Override
public Definition readWSDL(final URL wsdlURL)
throws WSDLException
{
WSDLFactory wsdlFactory = WSDLFactory.newInstance();
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", false);
return reader.readWSDL(wsdlURL.toString());
}
protected Definition getDefinition(final Endpoint endpoint)
{
final Bus bus = BUS_FACTORY.getBus(endpoint) ;
final ServerRegistry serverRegistry = bus.getExtension(ServerRegistry.class) ;
final String address = endpoint.getAddress() ;
final EndpointInfo endpointInfo = getEndpointInfo(address, serverRegistry) ;
if (endpointInfo != null)
{
final ServiceInfo serviceInfo = endpointInfo.getService() ;
final ServiceWSDLBuilder serviceWSDLBuilder = new ServiceWSDLBuilder(bus, serviceInfo) ;
try
{
return serviceWSDLBuilder.build() ;
}
catch (final WSDLException wsdle)
{
throw new IllegalStateException("Failed to generate WSDL", wsdle) ;
}
}
return null ;
}
protected EndpointInfo getEndpointInfo(final String address, final ServerRegistry serverRegistry)
{
if (address != null)
{
final List<Server> servers = serverRegistry.getServers() ;
if (servers != null)
{
for(Server server: servers)
{
final EndpointInfo endpointInfo = server.getEndpoint().getEndpointInfo() ;
if (address.equals(endpointInfo.getAddress()))
{
return endpointInfo ;
}
}
}
}
return null ;
}
private void initialiseContextClassLoader(final Endpoint endpoint)
{
if (JBossDeployerUtil.isWebMetaDataPresent())
{
final ClassLoader tccl = JBossWSFactory.getFactory().getClassLoader(endpoint) ;
if (tccl != null)
{
Thread.currentThread().setContextClassLoader(tccl) ;
return ;
}
throw new IllegalStateException("Could not locate ENC ClassLoader for service endpoint.") ;
}
}
private interface BusFactory
{
public Bus getBus(final Endpoint endpoint) ;
}
private static final class BusHolderFactory implements BusFactory
{
public Bus getBus(final Endpoint endpoint)
{
final BusHolder busHolder = endpoint.getService().getDeployment().getAttachment(BusHolder.class) ;
return busHolder.getBus() ;
}
}
private static final class BusExtensionFactory implements BusFactory
{
public Bus getBus(final Endpoint endpoint)
{
final Map<Class<?>, Object> extensions = endpoint.getAttachment(Map.class) ;
final Bus bus = (extensions == null ? null : (Bus) extensions.get(Bus.class)) ;
if (bus == null)
{
LOGGER.error("CXF Bus not present in endpoint attachments. Has the CXF integration bean configured? See ESB documentation for details.") ;
throw new IllegalStateException("Could not locate CXF Bus attachment") ;
}
return bus ;
}
}
static
{
boolean busHolderExists = false ;
try
{
ClassUtil.forName("org.jboss.wsf.stack.cxf.configuration.BusHolder", ServletControllerExtProviderFactory.class) ;
busHolderExists = true ;
}
catch (final Throwable th) {} // ignore
if (busHolderExists)
{
BUS_FACTORY = new BusHolderFactory() ;
}
else
{
BUS_FACTORY = new BusExtensionFactory() ;
}
}
}