/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., 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.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.services.soapui;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.wsdl.Definition;
import javax.wsdl.Import;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.httpclient.HttpClient;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.jboss.internal.soa.esb.soap.OGNLUtils;
import org.jboss.internal.soa.esb.util.ESBProperties;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCache;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCacheResource;
import org.jboss.internal.soa.esb.util.XMLHelper;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCache.LRUReferenceCountCacheEntry;
import org.jboss.internal.soa.esb.util.stax.events.ESBStaxXMLEvent;
import org.jboss.internal.soa.esb.util.stax.util.ESBXMLEventStreamReader;
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.dom.YADOMUtil;
import org.jboss.soa.esb.http.HttpClientFactory;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.system.server.ServerConfig;
import org.jboss.system.server.ServerConfigImplMBean;
import org.milyn.Smooks;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
import com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil;
import com.eviware.soapui.impl.wsdl.support.xsd.SchemaException;
import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
import com.eviware.soapui.model.iface.MessagePart;
import com.eviware.soapui.model.iface.Operation;
import com.eviware.soapui.settings.WsdlSettings;
/**
* Soap UI Soap Client Service MBean.
*
* @author <a href="mailto:tom.fennelly@jboss.com">tom.fennelly@jboss.com</a>
*/
public class SoapUIClientService extends ServiceMBeanSupport implements SoapUIClientServiceMBean {
private static final String FAULT_PREFIX = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<soapenv:Body><soapenv:Fault><faultcode>?</faultcode><faultstring>?</faultstring><detail>" ;
private static final String FAULT_SUFFIX = "</detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>" ;
private static final String IS_CLONE_ATTRIB = "is-clone";
private static Logger logger = Logger.getLogger(SoapUIClientService.class);
private final WsdlCache wsdlCache;
private final SmooksCache smooksCache;
private static final String SOAPUI_OPTIONAL_COMMENT = "Optional:";
private static final String REMOVE_POSTFIX = " to be removed";
private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
private static final String XMLSCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
private static final String NILLABLE_TAG_NAME = "nillable";
private static final String XMLNS_XSI = "xmlns:xsi";
private static final String XSI_NIL = "xsi:nil";
/**
* The SoapUI property file.
*/
private String propertyFile ;
/**
* The name of the generated property file.
*/
private static final String SOAP_UI_PROPERTY_FILE = "soapui-settings.xml" ;
/**
* The additional schema resources.
*/
private String schemas ;
private String serverDataDir;
/**
* The name of the SoapUI schema directory.
*/
private static final String SOAP_UI_SCHEMA_DIRECTORY = "soapui-schemas" ;
/**
* The name of the property specifying the created SoapUI schema directory.
*/
private static final String PROPERTY_ESB_SCHEMA_DIRECTORY = "jboss.esb.soapui.schema" ;
/**
* Public default constructor.
*/
public SoapUIClientService() throws ConfigurationException {
final ESBProperties properties = new ESBProperties("/soapui-client.sar.properties");
int smooksLRUCacheSize = properties.getIntProperty("smooks.lru.cache.size", 30);
smooksCache = new SmooksCache(smooksLRUCacheSize);
final int wsdlLRUCacheSize = properties.getIntProperty("wsdl.lru.cache.size", 30);
wsdlCache = new WsdlCache(wsdlLRUCacheSize);
}
protected void startService() throws Exception {
super.startService();
if (propertyFile != null) {
File dataDir;
if (serverDataDir != null) {
dataDir = new File(serverDataDir);
}
else {
final ServerConfig serverConfig = (ServerConfig) MBeanProxyExt.create(ServerConfig.class, ServerConfigImplMBean.OBJECT_NAME);
dataDir = serverConfig.getServerDataDir() ;
}
if (schemas != null)
{
initialiseSchemas(dataDir) ;
}
final File soapUIPropertyFile = new File(dataDir, SOAP_UI_PROPERTY_FILE) ;
final File baseFile = new File(propertyFile) ;
final InputStream xmlPropertyIS = getInputStream(baseFile);
try {
final FileOutputStream fos = new FileOutputStream(soapUIPropertyFile) ;
XMLHelper.replaceSystemProperties(XMLHelper.getXMLStreamReader(xmlPropertyIS),
XMLHelper.getXMLStreamWriter(fos)) ;
} finally {
xmlPropertyIS.close() ;
}
SoapUI.initSettings(soapUIPropertyFile.getAbsolutePath()) ;
}
}
@Override
protected void stopService() throws Exception
{
smooksCache.clean();
if (propertyFile != null)
{
File dataDir;
if (serverDataDir != null) {
dataDir = new File(serverDataDir);
}
else
{
final ServerConfig serverConfig = (ServerConfig) MBeanProxyExt.create(ServerConfig.class, ServerConfigImplMBean.OBJECT_NAME);
dataDir = serverConfig.getServerDataDir() ;
}
final File schemaDir = new File(dataDir, SOAP_UI_SCHEMA_DIRECTORY) ;
if (schemaDir.exists())
{
deleteFiles(schemaDir) ;
}
}
// TODO Auto-generated method stub
super.stopService();
}
private void initialiseSchemas(final File dataDir)
throws IOException
{
final String[] schemaResources = schemas.split("[, ]") ;
if (schemaResources != null)
{
final File schemaDir = new File(dataDir, SOAP_UI_SCHEMA_DIRECTORY) ;
schemaDir.mkdir();
for(String schema: schemaResources)
{
final File schemaFile = new File(schema) ;
final InputStream is = getInputStream(schemaFile) ;
try
{
writeToFile(is, schemaDir, schemaFile.getName()) ;
}
finally
{
is.close() ;
}
}
System.setProperty(PROPERTY_ESB_SCHEMA_DIRECTORY, schemaDir.getAbsolutePath()) ;
}
}
private void deleteFiles(final File file)
{
if (file.isDirectory())
{
final File[] files = file.listFiles() ;
for(File child: files)
{
deleteFiles(child) ;
}
}
file.delete() ;
}
private void writeToFile(final InputStream is, final File dir, final String name)
throws IOException
{
final File output = new File(dir, name) ;
final byte[] buffer = new byte[256] ;
final FileOutputStream fos = new FileOutputStream(output) ;
try
{
for(;;)
{
final int count = is.read(buffer) ;
if (count <= 0)
{
break ;
}
fos.write(buffer, 0, count) ;
}
}
finally
{
fos.close() ;
}
}
private InputStream getInputStream(final File file)
throws IOException
{
if (!file.isAbsolute()) {
final URL resourceURL = Thread.currentThread().getContextClassLoader().getResource(file.getPath()) ;
return resourceURL.openStream() ;
} else {
return new FileInputStream(file) ;
}
}
/**
* Get the property file.
* @return The name of the property file being used.
*/
public String getPropertyFile()
{
return propertyFile ;
}
/**
* Set the property file.
* @param propertyFile The name of the property file being used.
*/
public void setPropertyFile(final String propertyFile)
{
this.propertyFile = propertyFile ;
}
/**
* Get the additional schema resources.
* @return The additional schema resources.
*/
public String getSchemas()
{
return schemas ;
}
/**
* Set the additional schemes.
* @param schemas The additional schema resources to setup for SoapUI.
* This needs support through the soapui-settings.xml file
* @see setPropertyFile
*/
public void setSchemas(final String schemas)
{
this.schemas = schemas ;
}
/**
* Build a SOAP request for the specified operation on the specified WSDL.
*
* @param wsdl WSDL URL.
* @param operation Operation name.
* @param serviceName Service Name.
* @param params Message parameter map.
* @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
* @param smooksResource {@link org.milyn.Smooks} transformation configuration resource. This is the actual
* Smooks resource configuration XML, not a file name.
* Null if no transformations are to be performed on the SOAP message before serializing it
* for return.
* @param soapNs optional SOAP namespace
* @return The SOAP Message.
* @throws IOException Failed to load WSDL.
*/
public String buildRequest(String wsdl, String operation, String serviceName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
final XMLEventReader reader = state.getRequest(operation, serviceName, true, wsdl, httpClientProps) ;
return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
/**
* Use soapUI to build a SOAP response for the specified operation on the specified WSDL.
*
* @param wsdl WSDL URL
* @param operation Operation name.
* @param serviceName Service Name.
* @param params Message parameter map.
* @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
* @param smooksResource {@link org.milyn.Smooks} transformation configuration resource file.
* Null if no transformations are to be performed on the SOAP message before serializing it
* for return.
* @param soapNs optional SOAP namespace
* @return The SOAP Message.
* @throws IOException Failed to load WSDL.
* @throws UnsupportedOperationException Operation not supported on specified WSDL.
* @throws SAXException Failed to parse the SOAP UI generated request message.
*/
public String buildResponse(String wsdl, String operation, String serviceName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
final XMLEventReader reader = state.getResponse(operation, serviceName, true, wsdl, httpClientProps) ;
return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
public String buildFault(String wsdl, String operation, String serviceName, String faultName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
params.put("Fault.faultcode","soapenv:server");
try
{
final WsdlState state = wsdlEntry.getResource() ;
final XMLEventReader reader = state.getFault(operation, serviceName, faultName, true, wsdl, httpClientProps) ;
return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
/**
* Get the 1st endpoint from the specified WSDL.
*
* @param wsdl WSDL URL.
* @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
* @return The operation endpoint URL.
* @throws IOException Failed to load WSDL.
*/
public String getEndpoint(String wsdl, String serviceName, Properties httpClientProps) throws IOException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
if(serviceName != null)
{
return state.getEndpoint(serviceName, true, true, wsdl, httpClientProps);
}
else
{
return state.getDefaultEndpoint() ;
}
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
/**
* Get the Content Type for the appropriate SOAP version of the 1st interface from the specified WSDL.
*
* @param wsdl WSDL URL.
* @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
* @return The operation endpoint URL.
* @throws IOException Failed to load WSDL.
*/
public String getContentType(String wsdl, String serviceName, Properties httpClientProps) throws IOException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
if(serviceName != null)
{
return state.getContentType(serviceName, true, true, wsdl, httpClientProps);
}
else
{
return state.getDefaultContentType() ;
}
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
/**
* Use soapUI to Merge a SOAP response for the specified operation on the specified WSDL with its template.
*
* @param wsdl WSDL URL.
* @param operation Operation name.
* @param serviceName Service Name.
* @param response The actual response.
* @param smooksResource {@link org.milyn.Smooks} transformation configuration resource file.
* Null if no transformations are to be performed on the SOAP message before serializing it
* for return.
* @param soapNs optional SOAP namespace
* @return The SOAP Message.
* @throws IOException Failed to load WSDL.
* @throws UnsupportedOperationException Operation not supported on specified WSDL.
* @throws SAXException Failed to parse the SOAP UI generated request message.
*/
public String mergeResponseTemplate(String wsdl, String operation, String serviceName, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
final XMLEventReader reader = state.getResponse(operation, serviceName, true, wsdl, httpClientProps) ;
return (reader == null ? response : mergeSOAPMessage(reader, response, smooksResource, soapNs));
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
WsdlOperationInfo getOperationInfo(final String wsdl, final String operationName , final String serviceName,
final Properties httpClientProps, final boolean refresh)
throws IOException
{
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
try
{
final WsdlState state = wsdlEntry.getResource() ;
final WsdlServiceInfo serviceInfo = state.getServiceInfo(serviceName, refresh, true, wsdl, httpClientProps) ;
return serviceInfo.getOperation(operationName) ;
}
finally
{
wsdlCache.release(wsdlEntry) ;
}
}
static Set<QName> extractNillableElements(final String wsdl, final EsbWsdlLoader loader)
throws SchemaException, IOException
{
final Set<QName> nils = new HashSet<QName>() ;
Map<String, XmlObject> schemas = SchemaUtils.getSchemas(wsdl, loader);
Iterator keys = schemas.keySet().iterator();
while (keys.hasNext()) {
XmlObject schema = schemas.get(keys.next());
String namespace = SchemaUtils.getTargetNamespace(schema);
Document doc = getDocument(schema.toString());
Element docRoot = doc.getDocumentElement();
extractNillableElements(docRoot, nils, namespace);
}
return nils ;
}
static void extractNillableElements(Element element, Set<QName> nils, String namespace) {
if (element != null
&& element.getLocalName()!= null
&& element.getLocalName().equals("element")
&& element.hasAttribute(NILLABLE_TAG_NAME)
&& element.getAttribute(NILLABLE_TAG_NAME).equals("true")) {
nils.add(new QName(namespace, element.getAttribute("name")));
}
NodeList children = element.getChildNodes();
int childCount = children.getLength();
for(int i = 0; i < childCount; i++) {
Node child = children.item(i);
if(child.getNodeType() == Node.ELEMENT_NODE) {
extractNillableElements((Element) child, nils, namespace);
}
}
}
private String buildSOAPMessage(XMLEventReader reader, Map params, String smooksResource, String soapNs, Set<QName> nils) throws IOException, SAXException {
Document messageDoc = getDocument(reader) ;
Element docRoot = messageDoc.getDocumentElement();
// Purposely not using log levels to output because I want to make
// it as easy as possible for the developer to dump the SOAP during dev. They
// just need to set "dumpSOAP" in the param Map....
boolean dumpSOAP = params.containsKey("dumpSOAP");
if(dumpSOAP) {
dumpSOAP("SOAP Template (Unexpanded):", docRoot);
}
expandMessage(docRoot, params);
if(dumpSOAP) {
dumpSOAP("SOAP Template (Expanded):", docRoot);
}
injectParameters(docRoot, params, soapNs, nils);
if(smooksResource != null) {
applySmooksTransform(smooksResource, messageDoc);
// reassign the docRoot variable after transform... in case it was replaced by a #document transform...
docRoot = messageDoc.getDocumentElement();
}
if(dumpSOAP) {
dumpSOAP("SOAP Message (Populated Template):", docRoot);
}
try
{
final StringWriter sw = new StringWriter() ;
final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
XMLHelper.readDomNode(docRoot, writer, true) ;
return sw.toString();
}
catch (final XMLStreamException xmlse)
{
final IOException ioe = new IOException("Failed to serialize the output SOAP message") ;
ioe.initCause(xmlse) ;
throw ioe ;
}
}
private String mergeSOAPMessage(XMLEventReader reader, String response, String smooksResource, String soapNs) throws IOException, SAXException {
Document templateDoc = getDocument(reader);
Element templateRoot = templateDoc.getDocumentElement();
Document messageDoc = getDocument(response);
Element messageRoot = messageDoc.getDocumentElement();
debugDoc(messageRoot);
debugDoc(templateRoot);
mergeTemplate(templateRoot, messageRoot, 0);
if(smooksResource != null) {
applySmooksTransform(smooksResource, messageDoc);
}
debugDoc(messageRoot);
try
{
final StringWriter sw = new StringWriter() ;
final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
XMLHelper.readDomNode(messageRoot, writer, true) ;
return sw.toString();
}
catch (final XMLStreamException xmlse)
{
final IOException ioe = new IOException("Failed to serialize the output SOAP message") ;
ioe.initCause(xmlse) ;
throw ioe ;
}
}
private void debugDoc(Element doc)
{
if(logger.isDebugEnabled()) {
logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
try {
final StringWriter sw = new StringWriter() ;
final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
XMLHelper.readDomNode(doc, writer, true) ;
logger.debug(sw.toString());
} catch (final XMLStreamException xmlse) {
logger.debug("Failed to print the SOAP message") ;
}
logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
}
}
/**
* Merge the template to accommodate data collections.
* <p/>
* It merges the soapUI cllection comment nodes to the message where appropriate.
*
* @param template The template element to be merged.
* @param instance The element to be processed.
* @param index The template's element instance index.
*/
private void mergeTemplate(Element template, Element instance, int index) {
if (template != null && instance != null) {
if (index == 0) {
//Process only if this is the first element of its kind
Comment comment = YADOMUtil.getCommentBefore(template);
if (comment != null
&& comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
Node parent = instance.getParentNode();
if (parent != null) {
Comment newComment = parent.getOwnerDocument().createComment(comment.getTextContent());
parent.insertBefore(newComment, instance);
}
}
}
NodeList children = template.getChildNodes();
int nodesCount = children.getLength();
for (int i = 0; i < nodesCount; i++) {
Node templateNode = children.item(i);
if (templateNode.getNodeType() == Node.ELEMENT_NODE) {
//We may have many instances of this template
//and each could have a nested collection so run through them
NodeList instances = instance.getElementsByTagNameNS(templateNode.getNamespaceURI(), templateNode.getLocalName());
int instancesSize = instances.getLength();
for (int j = 0; j < instancesSize; j++) {
mergeTemplate((Element) templateNode, (Element) instances.item(j), j);
}
}
}
}
}
private static Document getDocument(final XMLEventReader reader) throws IOException {
try {
return XMLHelper.createDocument(reader) ;
} catch (final Exception ex) {
final IOException ioe = new IOException("Failed to deserialize the SOAP message template") ;
ioe.initCause(ex) ;
throw ioe ;
}
}
private static Document getDocument(String soapMessageTemplate) throws IOException {
try {
final XMLEventReader reader = XMLHelper.getXMLEventReader(new StringReader(soapMessageTemplate)) ;
return XMLHelper.createDocument(reader) ;
} catch (final Exception ex) {
final IOException ioe = new IOException("Failed to deserialize the SOAP message template") ;
ioe.initCause(ex) ;
throw ioe ;
}
}
private void dumpSOAP(String message, Element docRoot) {
System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
System.out.println(message + "\n");
try {
final XMLEventWriter writer = XMLHelper.getXMLEventWriter(new StreamResult(System.out)) ;
XMLHelper.readDomNode(docRoot, writer, false) ;
} catch (Exception e) {
logger.error("Unable to dump SOAP.", e);
}
System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
}
private void applySmooksTransform(String smooksResource, Document messageDoc) throws IOException, SAXException {
if(smooksResource != null) {
LRUReferenceCountCacheEntry<Smooks, SmooksResource> smooksEntry = smooksCache.get(smooksResource);
try {
final Smooks smooks = smooksEntry.getResource();
smooks.filterSource(new DOMSource(messageDoc), new DOMResult());
}
finally
{
smooksCache.release(smooksEntry);
}
}
}
/**
* Expand the message to accommodate data collections.
* <p/>
* It basically just clones the message where appropriate.
*
* @param element The element to be processed.
* @param params The message params. Uses the message params to
* decide whether or not cloning is required.
*/
private void expandMessage(Element element, Map params) {
boolean elementRemoved = false;
// If this element is not a cloned element, check does it need to be cloned...
if (!element.hasAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, IS_CLONE_ATTRIB)) {
Element clonePoint = getClonePoint(element);
if(clonePoint != null) {
int collectionSize;
String ognl = OGNLUtils.getOGNLExpression(element);
//We don't need the index value when expanding the message
if (ognl.endsWith("]")) {
ognl = ognl.substring(0, ognl.lastIndexOf("["));
}
collectionSize = calculateCollectionSize(ognl, params);
if(collectionSize == -1) {
// It's a collection, but has no entries that match the OGNL expression for this element...
if(clonePoint == element) {
// If the clonePoint is the element itself, we remove it... we're done with it...
clonePoint.getParentNode().removeChild(clonePoint);
elementRemoved = true;
} else {
// If the clonePoint is not the element itself (it's a child element), leave it
// and check it again when we get to it...
resetClonePoint(clonePoint);
}
} else if(collectionSize == 0) {
// It's a collection, but has no entries, remove it...
clonePoint.getParentNode().removeChild(clonePoint);
elementRemoved = true;
} else if(collectionSize == 1) {
// It's a collection, but no need to clone coz we
// already have an entry for it...
clonePoint.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[0]");
} else {
cloneCollectionTemplateElement(clonePoint, (collectionSize - 1), ognl, params);
}
}
}
if (!elementRemoved){
// Now do the same for the child elements...
expandChildren(element, params);
}
}
private void expandChildren(Element element, Map params) {
List<Node> children = YADOMUtil.copyNodeList(element.getChildNodes());
for (Node node : children) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
expandMessage((Element) node, params);
}
}
}
private int calculateCollectionSize(String ognl, Map params) {
// Try for an Object graph based collection...
Object param = OGNLUtils.getParameter(ognl, params);
if (param != null) {
Class paramRuntime = param.getClass();
if (paramRuntime.isArray()) {
return ((Object[]) param).length;
} else if (Collection.class.isAssignableFrom(paramRuntime)) {
return ((Collection) param).size();
}
}
// Try for <String, Object> collection based map entries...
Set<Map.Entry> entries = params.entrySet();
String collectionPrefix = ognl + "[";
int maxIndex = -1;
for (Map.Entry entry : entries) {
Object keyObj = entry.getKey();
if(keyObj instanceof String) {
String key = (String)keyObj;
if(key.startsWith(collectionPrefix)) {
int endIndex = key.indexOf(']', collectionPrefix.length());
String ognlIndexValString = key.substring(collectionPrefix.length(), endIndex);
try {
int ognlIndexVal = Integer.valueOf(ognlIndexValString);
maxIndex = Math.max(maxIndex, ognlIndexVal);
} catch(NumberFormatException e) {}
}
}
}
if(maxIndex != -1) {
return maxIndex + 1;
}
// It's a collection, but nothing in this message for it collection...
return -1;
}
private Element getClonePoint(Element element) {
Comment comment;
// Is it this element...
comment = YADOMUtil.getCommentBefore(element);
if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
return element;
}
// Is it the first child element of this element...
Element firstChildElement = YADOMUtil.getFirstChildElement(element);
if(firstChildElement != null) {
Element lastChildElement = YADOMUtil.getLastChildElement(element);
comment = YADOMUtil.getCommentBefore(firstChildElement);
if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)
&& lastChildElement != null && firstChildElement.getTagName().equals(lastChildElement.getTagName())) {
comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
return firstChildElement;
}
}
return null;
}
private void resetClonePoint(Element clonePoint) {
Comment comment = YADOMUtil.getCommentBefore(clonePoint);
if(comment == null) {
throw new IllegalStateException("Call to reset a 'clonePoint' that doesn't have a comment before it.");
}
String commentText = comment.getTextContent();
if(!commentText.endsWith(OGNLUtils.CLONED_POSTFIX)) {
throw new IllegalStateException("Call to reset a 'clonePoint' that doesn't have a proper clone comment before it.");
}
comment.setTextContent(commentText.substring(0, commentText.length() - OGNLUtils.CLONED_POSTFIX.length()));
}
/**
* Clone a collection node.
* <p/>
* Note we have to frig with the OGNL expressions for collections/arrays because the
* collection entry is represented by [0], [1] etc in the OGNL expression, not the actual
* element name on the DOM e.g. collection node "order/items/item" (where "item" is the
* actual collection entry) maps to the OGNL expression "order.items[0]" etc.
*
* @param element The collection/array "entry" sub-branch.
* @param cloneCount The number of times it needs to be cloned.
* @param ognl The OGNL expression for the collection/array. Not including the
* indexing part.
* @param params The message params.
*/
private void cloneCollectionTemplateElement(Element element, int cloneCount, String ognl, Map params) {
if (element == null) {
return;
}
Node insertPoint = element.getNextSibling();
Node parent = element.getParentNode();
element.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[0]");
for (int i = 0; i < cloneCount; i++) {
Element clone = (Element) element.cloneNode(true);
clone.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + IS_CLONE_ATTRIB, "true");
clone.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[" + Integer.toString(i + 1) + "]");
if (insertPoint == null) {
parent.appendChild(clone);
} else {
parent.insertBefore(clone, insertPoint);
}
//The clones can have collections too, so we need to expand them here
expandChildren(clone, params);
}
}
private void injectParameters(Element element, Map params, String soapNs, Set<QName> nils) {
NodeList children = element.getChildNodes();
int childCount = children.getLength();
for (int i = 0; i < childCount; i++) {
Node node = children.item(i);
if (childCount == 1 && node.getNodeType() == Node.TEXT_NODE) {
if (isParameter(node)) {
String ognl = OGNLUtils.getOGNLExpression(element, soapNs);
Object param = OGNLUtils.getParameter(ognl, params);
if (param == null) {
Node parent = element.getParentNode();
String namespace = element.getNamespaceURI();
Node nsParent = parent;
while (nsParent != null && namespace == null) {
//Check the parents for the namespace
namespace = nsParent.getNamespaceURI();
nsParent = nsParent.getParentNode();
}
QName qname = new QName(namespace, element.getLocalName());
if (nils.contains(qname)) {
//If value is null and it is declared to be nillable set it as xsi:nil
element.getOwnerDocument().getDocumentElement().setAttributeNS(XMLNS_URI, XMLNS_XSI, XMLSCHEMA_INSTANCE_URI);
element.setAttributeNS(XMLSCHEMA_INSTANCE_URI, XSI_NIL, "true");
//Remove the soapUI's '?' text
element.removeChild(node);
} else {
Comment comment = YADOMUtil.getCommentBefore(element);
if(comment != null && comment.getTextContent().endsWith(SOAPUI_OPTIONAL_COMMENT)) {
//If it is optional do not generate the element
parent.removeChild(comment);
Comment clone = (Comment) comment.cloneNode(true);
clone.setTextContent(comment.getTextContent() + REMOVE_POSTFIX);
parent.insertBefore(clone, element);
} else {
//If it is required generate empty element
//Remove the soapUI's '?' text
element.removeChild(node);
}
}
} else {
element.removeChild(node);
element.appendChild(element.getOwnerDocument().createTextNode(param.toString()));
}
}
} else if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
NamedNodeMap attributes = node.getAttributes();
injectAttributeParameters(params, soapNs, node, attributes);
injectParameters((Element) node, params, soapNs, nils);
Comment comment = YADOMUtil.getCommentBefore((Element) node);
if(comment != null && comment.getTextContent().endsWith(SOAPUI_OPTIONAL_COMMENT + REMOVE_POSTFIX)) {
Node parent = node.getParentNode();
parent.removeChild(node);
parent.removeChild(comment);
childCount -= 2;
i -= 2;
}
}
}
element.removeAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, IS_CLONE_ATTRIB);
element.removeAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.OGNL_ATTRIB);
}
private void injectAttributeParameters(Map params, String soapNs, Node node, NamedNodeMap attributes) {
for (Node attribute : getNodes(attributes)) {
if (isParameter(attribute)) {
String localName = attribute.getLocalName();
String ognl = OGNLUtils.getOGNLExpression((Element)node, soapNs) + "." + localName;
Object param = OGNLUtils.getParameter(ognl, params);
if (param != null && param.toString().length() > 0) {
attribute.setTextContent(param.toString());
} else {
attributes.removeNamedItem(attribute.getNodeName());
}
}
}
}
private boolean isParameter(Node node) {
return node.getTextContent().equals("?");
}
private List<Node> getNodes(NamedNodeMap attributes) {
int len = attributes.getLength();
List<Node> list = new ArrayList<Node>(len);
for ( int a = 0 ; a < len ; a++)
{
list.add(attributes.item(a));
}
return list;
}
private static WsdlOperationInfo getWsdlOperationInfo(final Operation operation)
throws XMLStreamException
{
final WsdlOperation wsdlOperation = (WsdlOperation)operation ;
final String requestTemplate = wsdlOperation.createRequest(true);
final XMLEventReader requestReader = XMLHelper.getXMLEventReader(new StringReader(requestTemplate)) ;
final List<XMLEvent> requestEvents = ESBStaxXMLEvent.cloneStream(requestReader) ;
final String responseTemplate = wsdlOperation.createResponse(true);
final List<XMLEvent> responseEvents ;
if (responseTemplate != null)
{
final XMLEventReader responseReader = XMLHelper.getXMLEventReader(new StringReader(responseTemplate)) ;
responseEvents = ESBStaxXMLEvent.cloneStream(responseReader) ;
}
else
{
responseEvents = Collections.emptyList() ;
}
final MessagePart[] faultParts = wsdlOperation.getFaultParts();
final Map<String, List<XMLEvent>> faultEventsMap = new HashMap<String, List<XMLEvent>>() ;
final SoapMessageBuilder soapMessageBuilder = wsdlOperation.getInterface().getMessageBuilder();
final XmlObject detail = XmlObject.Factory.newInstance();
for(MessagePart messagePart: faultParts)
{
final MessagePart.FaultPart faultPart = (MessagePart.FaultPart)messagePart ;
final String faultName = faultPart.getName() ;
final SampleXmlUtil generator = new SampleXmlUtil(false) ;
generator.setExampleContent(false) ;
generator.setTypeComment(false) ;
final XmlCursor cursor = detail.newCursor();
cursor.toFirstContentToken() ;
generator.setTypeComment(true) ;
generator.setIgnoreOptional(wsdlOperation.getInterface().getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS ) );
for(Part part: faultPart.getWsdlParts())
{
try
{
soapMessageBuilder.createElementForPart(part, cursor, generator);
}
catch (final Exception ex)
{
throw new XMLStreamException("Unexpected exception creating fault template", ex) ;
}
}
final String faultTemplate = FAULT_PREFIX + detail.xmlText( new XmlOptions().setSaveAggressiveNamespaces().setSavePrettyPrint()) + FAULT_SUFFIX ;
final XMLEventReader faultReader = XMLHelper.getXMLEventReader(new StringReader(faultTemplate)) ;
final List<XMLEvent> faultEvents = ESBStaxXMLEvent.cloneStream(faultReader) ;
faultEventsMap.put(faultName, faultEvents) ;
}
return new WsdlOperationInfo(requestEvents, responseEvents,faultEventsMap) ;
}
private static Map<String, WsdlServiceInfo> getServiceInfoMap(final WsdlInterface[] wsdlInterfaces,
final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo)
throws Exception
{
final Map<String, WsdlServiceInfo> serviceInfoMap = new HashMap<String, WsdlServiceInfo> () ;
final Set<String> processed = new HashSet<String>() ;
final Map<QName, WsdlInterface> bindingsToInterface = new HashMap<QName, WsdlInterface>() ;
for(WsdlInterface wsdlInterface: wsdlInterfaces)
{
bindingsToInterface.put(wsdlInterface.getBindingName(), wsdlInterface) ;
}
for(WsdlInterface wsdlInterface: wsdlInterfaces)
{
final Definition definition = wsdlInterface.getWsdlContext().getDefinition() ;
processDefinition(definition, processed, bindingToOperationInfo, bindingsToInterface, serviceInfoMap) ;
}
return serviceInfoMap ;
}
private static void processDefinition(final Definition definition, final Set<String> processed,
final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo,
final Map<QName, WsdlInterface> bindingsToInterface,
final Map<String, WsdlServiceInfo> serviceInfoMap)
{
final String definitionLocation = definition.getDocumentBaseURI() ;
if (processed.add(definitionLocation))
{
final Map<?, Service> services = definition.getServices() ;
if (services != null)
{
for(Service service: services.values())
{
final Map<?, Port> ports = service.getPorts() ;
if (ports != null)
{
String endpoint = null ;
String contentType = null ;
boolean first = true ;
final Map<String, WsdlOperationInfo> operationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
for(Port port: ports.values())
{
final QName bindingName = port.getBinding().getQName() ;
if (first)
{
first = false ;
final WsdlInterface bindingWsdlInterface = bindingsToInterface.get(bindingName) ;
endpoint = bindingWsdlInterface.getEndpoints()[0] ;
contentType = bindingWsdlInterface.getSoapVersion().getContentType() ;
}
final Map<String, WsdlOperationInfo> bindingOperationInfoMap = bindingToOperationInfo.get(bindingName) ;
for(Map.Entry<String, WsdlOperationInfo> entry: bindingOperationInfoMap.entrySet())
{
final String operationName = entry.getKey() ;
final WsdlOperationInfo operationInfo = entry.getValue() ;
final WsdlOperationInfo current = operationInfoMap.put(operationName, operationInfo) ;
if (current != null)
{
operationInfoMap.put(operationName, current) ;
}
}
}
final WsdlServiceInfo serviceInfo = new WsdlServiceInfo(endpoint, contentType, operationInfoMap) ;
final String serviceName = service.getQName().toString() ;
serviceInfoMap.put(serviceName, serviceInfo) ;
}
}
}
final Map<?, List<Import>> allImports = definition.getImports() ;
if (allImports != null)
{
for(List<Import> imports: allImports.values())
{
for(Import current: imports)
{
processDefinition(current.getDefinition(), processed,
bindingToOperationInfo, bindingsToInterface, serviceInfoMap) ;
}
}
}
}
}
public void setServerDataDir(final String datadir)
{
this.serverDataDir = datadir;
}
public String getServerDataDir()
{
return serverDataDir;
}
/**
* Wrapper class for smooks resource.
*/
static class SmooksResource extends LRUReferenceCountCacheResource<Smooks>
{
SmooksResource(final Smooks smooks)
{
super(smooks) ;
}
public void close()
{
getInstance().close() ;
}
}
/**
* Smooks cache implementation.
*/
static class SmooksCache extends LRUReferenceCountCache<Smooks, SmooksResource>
{
SmooksCache(final int lruCacheSize)
{
super(lruCacheSize);
}
public LRUReferenceCountCacheEntry<Smooks, SmooksResource> get(final String resourceLocation)
throws UnsupportedEncodingException, SAXException, IOException
{
final LRUReferenceCountCacheEntry<Smooks, SmooksResource> entry = internalGet(resourceLocation) ;
if (entry != null)
{
return entry ;
}
else
{
return create(resourceLocation, createResource(resourceLocation)) ;
}
}
protected SmooksResource createResource(final String resourceLocation)
throws UnsupportedEncodingException, SAXException, IOException
{
final Smooks smooks = new Smooks();
smooks.addConfigurations("smooks-resource", new ByteArrayInputStream(resourceLocation.getBytes("UTF-8")));
return new SmooksResource(smooks) ;
}
}
/**
* Cached operation information.
*/
static class WsdlOperationInfo
{
/**
* request event stream.
*/
private final List<XMLEvent> requestEvents ;
/**
* response event stream.
*/
private final List<XMLEvent> responseEvents ;
/**
* fault event streams.
*/
private final Map<String, List<XMLEvent>> faultEventsMap ;
WsdlOperationInfo(final List<XMLEvent> requestEvents, final List<XMLEvent> responseEvents,
final Map<String, List<XMLEvent>> faultEventsMap)
{
this.requestEvents = requestEvents ;
this.responseEvents = responseEvents ;
this.faultEventsMap = faultEventsMap ;
}
public List<XMLEvent> getRequestEvents()
{
return requestEvents ;
}
public List<XMLEvent> getResponseEvents()
{
return responseEvents ;
}
public List<XMLEvent> getFaultEvents(final String faultName)
{
return faultEventsMap.get(faultName) ;
}
}
/**
* Cached service info.
*/
static class WsdlServiceInfo
{
/**
* First endpoint.
*/
private final String endpoint ;
/**
* Content type for service.
*/
private final String contentType ;
/**
* Cached operation information.
*/
private final Map<String, WsdlOperationInfo> operationInfoMap ;
WsdlServiceInfo(final String endpoint, final String contentType, final Map<String, WsdlOperationInfo> operationInfoMap)
{
this.endpoint = endpoint ;
this.contentType = contentType ;
this.operationInfoMap = operationInfoMap ;
}
public String getEndpoint()
{
return endpoint ;
}
public String getContentType()
{
return contentType ;
}
public WsdlOperationInfo getOperation(final String operation)
{
return operationInfoMap.get(operation) ;
}
}
/**
* Internal WSDL state class to allow atomic swapping out during refresh operations.
*/
static class WsdlInternalState
{
private final Set<QName> nils ;
private final Map<String, WsdlServiceInfo> serviceInfoMap ;
private final Map<String, WsdlOperationInfo> operationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
private final String defaultContentType ;
private final String defaultEndpoint ;
public WsdlInternalState(final String wsdl, final Properties httpClientProps)
throws IOException
{
try {
final WsdlProject wsdlProject = new WsdlProject();
final HttpClient httpClient = HttpClientFactory.createHttpClient(httpClientProps);
try {
EsbWsdlLoader loader = new EsbWsdlLoader(wsdl, httpClient);
WsdlLoaderAspect.set(loader); // JBESB-3276
final WsdlInterface[] wsdlInterfaces = wsdlProject.importWsdl(wsdl, true, loader);
nils = extractNillableElements(wsdl, loader) ;
defaultContentType = wsdlInterfaces[0].getSoapVersion().getContentType() ;
defaultEndpoint = wsdlInterfaces[0].getEndpoints()[0] ;
final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo = new HashMap<QName, Map<String, WsdlOperationInfo>>() ;
for(WsdlInterface wsdlInterface: wsdlInterfaces)
{
final Map<String, WsdlOperationInfo> bindingOperationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
for (Operation operation: wsdlInterface.getOperations())
{
final String name = operation.getName() ;
// we cannot disambiguate further than name, so ignore subsequent ones
if (!bindingOperationInfoMap.containsKey(name))
{
final WsdlOperationInfo info = getWsdlOperationInfo(operation) ;
bindingOperationInfoMap.put(name, info) ;
final WsdlOperationInfo current = operationInfoMap.put(name, info) ;
// Restore first operation detail if already set
if (current != null)
{
operationInfoMap.put(name, current) ;
}
}
}
bindingToOperationInfo.put(wsdlInterface.getBindingName(), bindingOperationInfoMap) ;
}
serviceInfoMap = getServiceInfoMap(wsdlInterfaces, bindingToOperationInfo) ;
} finally {
WsdlLoaderAspect.unset(); // JBESB-3276
HttpClientFactory.shutdown(httpClient);
}
} catch (Exception e) {
IOException ioException = new IOException("Failed to create WSDL state.");
ioException.initCause(e);
throw ioException;
}
}
public XMLEventReader getRequest(final String operation, final String serviceName)
{
final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
if (operationInfo != null)
{
return new ESBXMLEventStreamReader(operationInfo.getRequestEvents()) ;
}
return null ;
}
public XMLEventReader getResponse(final String operation, final String serviceName)
{
final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
if (operationInfo != null)
{
return new ESBXMLEventStreamReader(operationInfo.getResponseEvents()) ;
}
return null ;
}
public XMLEventReader getFault(final String faultName, final String operation, final String serviceName)
{
final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
if (operationInfo != null)
{
final List<XMLEvent> events = operationInfo.getFaultEvents(faultName) ;
if (events != null)
{
return new ESBXMLEventStreamReader(events) ;
}
}
return null ;
}
public String getDefaultContentType()
{
return defaultContentType ;
}
public String getDefaultEndpoint()
{
return defaultEndpoint ;
}
public WsdlOperationInfo getOperationInfo(final String serviceName, final String operation)
{
if (serviceName != null)
{
final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName) ;
if (serviceInfo != null)
{
return serviceInfo.getOperation(operation) ;
}
return null ;
}
else
{
return operationInfoMap.get(operation) ;
}
}
public WsdlServiceInfo getServiceInfo(final String serviceName)
{
return serviceInfoMap.get(serviceName) ;
}
public Set<QName> getNils()
{
return nils ;
}
}
/**
* WSDL state class supporting refresh of internal state.
*/
static class WsdlState
{
private volatile WsdlInternalState state ;
WsdlState(final String wsdl, final Properties httpClientProps)
throws IOException
{
state = new WsdlInternalState(wsdl, httpClientProps) ;
}
public XMLEventReader getRequest(final String operation, final String serviceName,
final boolean refresh, final String wsdl, final Properties httpClientProps)
throws IOException
{
final XMLEventReader reader = state.getRequest(operation, serviceName) ;
if (reader != null)
{
return reader ;
}
else if (refresh)
{
state = new WsdlInternalState(wsdl, httpClientProps) ;
return getRequest(operation, serviceName, false, null, null) ;
}
else
{
throw new UnsupportedOperationException("Operation '" + operation + "' not found in service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
}
}
public XMLEventReader getResponse(final String operation, final String serviceName,
final boolean refresh, final String wsdl, final Properties httpClientProps)
throws IOException
{
final XMLEventReader reader = state.getResponse(operation, serviceName) ;
if (reader != null)
{
return (reader.hasNext() ? reader : null) ;
}
else if (refresh)
{
state = new WsdlInternalState(wsdl, httpClientProps) ;
return getResponse(operation, serviceName, false, null, null) ;
}
else
{
throw new UnsupportedOperationException("Operation '" + operation + "' not found in service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
}
}
public XMLEventReader getFault(final String operation, final String serviceName,
final String faultName, final boolean refresh, final String wsdl, final Properties httpClientProps)
throws IOException
{
final XMLEventReader reader = state.getFault(faultName, operation, serviceName) ;
if (reader != null)
{
return reader ;
}
else if (refresh)
{
state = new WsdlInternalState(wsdl, httpClientProps) ;
return getFault(operation, serviceName, faultName, false, null, null) ;
}
else
{
throw new UnsupportedOperationException("Fault '" + faultName + "' not found in operation '" + operation + "' from service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
}
}
public String getDefaultContentType()
{
return state.getDefaultContentType() ;
}
public String getContentType(final String serviceName, final boolean refresh, final boolean fail,
final String wsdl, final Properties httpClientProps)
throws IOException
{
final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName, refresh, fail, wsdl, httpClientProps) ;
if (serviceInfo != null)
{
return serviceInfo.getContentType() ;
}
else
{
return null ;
}
}
public String getDefaultEndpoint()
{
return state.getDefaultEndpoint() ;
}
public String getEndpoint(final String serviceName, final boolean refresh, final boolean fail,
final String wsdl, final Properties httpClientProps)
throws IOException
{
final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName, refresh, fail, wsdl, httpClientProps) ;
if (serviceInfo != null)
{
return serviceInfo.getEndpoint() ;
}
else
{
return null ;
}
}
public WsdlServiceInfo getServiceInfo(final String serviceName, final boolean refresh, final boolean fail, final String wsdl, final Properties httpClientProps)
throws IOException
{
final WsdlServiceInfo serviceInfo = state.getServiceInfo(serviceName) ;
if (serviceInfo != null)
{
return serviceInfo ;
}
else if (refresh)
{
state = new WsdlInternalState(wsdl, httpClientProps) ;
return getServiceInfo(serviceName, false, fail, wsdl, httpClientProps) ;
}
else if (fail)
{
throw new UnsupportedOperationException("Service '" + serviceName + "' not defined in WSDL '" + wsdl + "'.");
}
else
{
return null ;
}
}
public Set<QName> getNils()
{
return state.getNils() ;
}
}
/**
* Wrapper class for WSDL state resource.
*/
static class WsdlResource extends LRUReferenceCountCacheResource<WsdlState>
{
WsdlResource(final WsdlState state)
{
super(state) ;
}
}
/**
* WSDL cache implementation.
*/
static class WsdlCache extends LRUReferenceCountCache<WsdlState, WsdlResource>
{
WsdlCache(final int lruCacheSize)
{
super(lruCacheSize);
}
public LRUReferenceCountCacheEntry<WsdlState, WsdlResource> get(final String wsdl, final Properties httpProperties)
throws IOException
{
final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> entry = internalGet(wsdl) ;
if (entry != null)
{
return entry ;
}
else
{
return create(wsdl, createResource(wsdl, httpProperties)) ;
}
}
protected WsdlResource createResource(final String wsdl, final Properties httpProperties)
throws IOException
{
return new WsdlResource(new WsdlState(wsdl, httpProperties)) ;
}
}
}