/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY 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 along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ws.metadata.umdm;
// $Id: ServiceMetaData.java 8113 2008-08-19 12:59:14Z darran.lofthouse@jboss.com $
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import org.jboss.logging.Logger;
import org.jboss.ws.WSException;
import org.jboss.ws.core.binding.TypeMappingImpl;
import org.jboss.ws.core.jaxrpc.TypeMappingRegistryImpl;
import org.jboss.ws.core.jaxrpc.binding.jbossxb.SchemaBindingBuilder;
import org.jboss.ws.core.soap.Use;
import org.jboss.ws.metadata.jaxrpcmapping.JavaWsdlMapping;
import org.jboss.ws.metadata.jaxrpcmapping.JavaWsdlMappingFactory;
import org.jboss.ws.metadata.wsdl.WSDLDefinitions;
import org.jboss.ws.metadata.wsdl.WSDLTypes;
import org.jboss.ws.metadata.wsdl.WSDLUtils;
import org.jboss.ws.metadata.wsdl.xmlschema.JBossXSModel;
import org.jboss.ws.metadata.wsse.WSSecurityConfiguration;
import org.jboss.ws.tools.wsdl.WSDLDefinitionsFactory;
import org.jboss.wsf.spi.deployment.UnifiedVirtualFile;
import org.jboss.wsf.spi.metadata.j2ee.serviceref.UnifiedHandlerMetaData.HandlerType;
import org.jboss.xb.binding.sunday.unmarshalling.SchemaBinding;
/**
* A Service component describes a set of endpoints.
*
* @author Thomas.Diesler@jboss.org
* @since 12-May-2005
*/
public class ServiceMetaData implements InitalizableMetaData
{
// provide logging
private static final Logger log = Logger.getLogger(ServiceMetaData.class);
// The parent meta data.
private UnifiedMetaData wsMetaData;
// The service endpoints
private Map<QName, EndpointMetaData> endpoints = new LinkedHashMap<QName, EndpointMetaData>();
private QName serviceName;
private String serviceRefName;
private String wsdName;
private URL wsdlLocation;
private String wsdlFile;
private URL mappingLocation;
private String wsdlPublishLocation;
// The optional service handlers
private List<HandlerMetaDataJAXWS> handlers = new ArrayList<HandlerMetaDataJAXWS>();
// The type mapping that is maintained by this service
private TypesMetaData types;
private TypeMappingRegistry tmRegistry = new TypeMappingRegistryImpl();
private SchemaBinding schemaBinding;
// Arbitrary properties given by <call-property>
private Properties properties;
// derived cached encoding style
private Use encStyle;
// The security configuration
private WSSecurityConfiguration securityConfig;
// The key to the wsdl cache
private String wsdlCacheKey;
public ServiceMetaData(UnifiedMetaData wsMetaData, QName serviceName)
{
this.wsMetaData = wsMetaData;
this.serviceName = serviceName;
this.types = new TypesMetaData(this);
}
public UnifiedMetaData getUnifiedMetaData()
{
return wsMetaData;
}
public void setServiceName(QName serviceName)
{
this.serviceName = serviceName;
}
public QName getServiceName()
{
return serviceName;
}
public String getServiceRefName()
{
return serviceRefName;
}
public void setServiceRefName(String serviceRefName)
{
this.serviceRefName = serviceRefName;
}
public String getWebserviceDescriptionName()
{
return wsdName;
}
public void setWebserviceDescriptionName(String wsdName)
{
this.wsdName = wsdName;
}
public String getWsdlFile()
{
return wsdlFile;
}
public void setWsdlFile(String wsdlFile)
{
this.wsdlFile = wsdlFile;
}
public URL getWsdlLocation()
{
return wsdlLocation;
}
public void setWsdlLocation(URL wsdlLocation)
{
this.wsdlLocation = wsdlLocation;
}
public String getWsdlPublishLocation()
{
return wsdlPublishLocation;
}
public void setWsdlPublishLocation(String wsdlPublishLocation)
{
this.wsdlPublishLocation = wsdlPublishLocation;
}
public Properties getProperties()
{
return properties;
}
public void setProperties(Properties properties)
{
this.properties = properties;
}
public TypesMetaData getTypesMetaData()
{
return types;
}
public void addHandler(HandlerMetaDataJAXWS handler)
{
handlers.add(handler);
}
public List<HandlerMetaDataJAXWS> getHandlerMetaData()
{
return Collections.unmodifiableList(handlers);
}
public List<EndpointMetaData> getEndpoints()
{
return new ArrayList<EndpointMetaData>(endpoints.values());
}
public EndpointMetaData getEndpoint(QName portName)
{
return endpoints.get(portName);
}
public EndpointMetaData removeEndpoint(QName portName)
{
return endpoints.remove(portName);
}
public EndpointMetaData getEndpointByServiceEndpointInterface(String seiName)
{
EndpointMetaData epMetaData = null;
for (EndpointMetaData epmd : endpoints.values())
{
if (seiName.equals(epmd.getServiceEndpointInterfaceName()))
{
if (epMetaData != null)
{
// The CTS uses Service.getPort(Class) with multiple endpoints implementing the same SEI
log.warn("Multiple possible endpoints implementing SEI: " + seiName);
}
epMetaData = epmd;
}
}
return epMetaData;
}
public void addEndpoint(EndpointMetaData epMetaData)
{
QName portName = epMetaData.getPortName();
// This happends when we have multiple port components in sharing the same wsdl port
// The EndpointMetaData name is the wsdl port, so we cannot have multiple meta data for the same port.
if (endpoints.get(portName) != null)
throw new WSException("EndpointMetaData name must be unique: " + portName);
endpoints.put(portName, epMetaData);
}
public URL getMappingLocation()
{
return mappingLocation;
}
public void setMappingLocation(URL mappingLocation)
{
this.mappingLocation = mappingLocation;
}
public JavaWsdlMapping getJavaWsdlMapping()
{
JavaWsdlMapping javaWsdlMapping = null;
if (mappingLocation != null)
{
javaWsdlMapping = (JavaWsdlMapping)wsMetaData.getMappingDefinition(mappingLocation.toExternalForm());
if (javaWsdlMapping == null)
{
try
{
JavaWsdlMappingFactory mappingFactory = JavaWsdlMappingFactory.newInstance();
javaWsdlMapping = mappingFactory.parse(mappingLocation);
wsMetaData.addMappingDefinition(mappingLocation.toExternalForm(), javaWsdlMapping);
}
catch (IOException e)
{
throw new WSException("Cannot parse jaxrpc-mapping.xml", e);
}
}
}
return javaWsdlMapping;
}
/**
* Get the wsdl definition that corresponds to the wsdl-file element.
*/
public WSDLDefinitions getWsdlDefinitions()
{
URL wsdlURL = getWsdlFileOrLocation();
WSDLDefinitions wsdlDefinitions = null;
if (wsdlURL != null)
{
// The key should not after it is assigned
if (wsdlCacheKey == null)
wsdlCacheKey = "#" + (wsdlLocation != null ? wsdlLocation : wsdlFile);
wsdlDefinitions = (WSDLDefinitions)wsMetaData.getWsdlDefinition(wsdlCacheKey);
if (wsdlDefinitions == null)
{
WSDLDefinitionsFactory factory = WSDLDefinitionsFactory.newInstance();
wsdlDefinitions = factory.parse(wsdlURL);
wsMetaData.addWsdlDefinition(wsdlCacheKey, wsdlDefinitions);
}
}
return wsdlDefinitions;
}
public URL getWsdlFileOrLocation()
{
URL wsdlURL = wsdlLocation;
if (wsdlURL == null && wsdlFile != null)
{
// Try wsdlFile as URL
try
{
wsdlURL = new URL(wsdlFile);
}
catch (MalformedURLException e)
{
// ignore
}
// Try wsdlFile as child from root
if (wsdlURL == null)
{
try
{
UnifiedVirtualFile vfsRoot = getUnifiedMetaData().getRootFile();
wsdlURL = vfsRoot.findChild(wsdlFile).toURL();
}
catch (IOException ex)
{
throw new IllegalStateException("Cannot find wsdl: " + wsdlFile);
}
}
}
return wsdlURL;
}
public TypeMappingImpl getTypeMapping()
{
Use encStyle = getEncodingStyle();
TypeMappingImpl typeMapping = (TypeMappingImpl)tmRegistry.getTypeMapping(encStyle.toURI());
if (typeMapping == null)
throw new WSException("No type mapping for encoding style: " + encStyle);
return typeMapping;
}
public WSSecurityConfiguration getSecurityConfiguration()
{
return securityConfig;
}
public void setSecurityConfiguration(WSSecurityConfiguration securityConfiguration)
{
this.securityConfig = securityConfiguration;
}
public Use getEncodingStyle()
{
if (encStyle == null)
{
if (endpoints.size() > 0)
{
for (EndpointMetaData epMetaData : endpoints.values())
{
if (encStyle == null)
{
encStyle = epMetaData.getEncodingStyle();
}
else if (encStyle.equals(epMetaData.getEncodingStyle()) == false)
{
throw new WSException("Conflicting encoding styles not supported");
}
}
}
else
{
encStyle = Use.LITERAL;
}
}
return encStyle;
}
public SchemaBinding getSchemaBinding()
{
JavaWsdlMapping wsdlMapping = getJavaWsdlMapping();
if (schemaBinding == null && getEncodingStyle() == Use.LITERAL && wsdlMapping != null)
{
JBossXSModel xsModel = types.getSchemaModel();
SchemaBindingBuilder bindingBuilder = new SchemaBindingBuilder();
schemaBinding = bindingBuilder.buildSchemaBinding(xsModel, wsdlMapping);
}
return schemaBinding;
}
public void validate()
{
// Validate that there is at least one handler configured
// if we have a security configuration
if (securityConfig != null)
{
int handlerCount = 0;
for (EndpointMetaData epMetaData : endpoints.values())
{
handlerCount += epMetaData.getHandlerMetaData(HandlerType.ALL).size();
}
if (handlerCount == 0)
log.warn("WS-Security requires a security handler to be configured");
}
// Validate endpoints
for (EndpointMetaData epMetaData : endpoints.values())
epMetaData.validate();
}
/**
* @see UnifiedMetaData#eagerInitialize()
*/
public void eagerInitialize()
{
// Initialize all wsdl definitions and schema objects
WSDLDefinitions definitions = getWsdlDefinitions();
if (definitions != null)
{
WSDLTypes types = definitions.getWsdlTypes();
if (types != null)
{
JBossXSModel model = WSDLUtils.getSchemaModel(types);
if (model != null)
model.eagerInitialize();
}
}
// Initialize jaxrpc-mapping data
getJavaWsdlMapping();
// Initialize endpoints
for (EndpointMetaData epMetaData : endpoints.values())
epMetaData.eagerInitialize();
// Initialize schema binding
getSchemaBinding();
}
/** Assert that the given namespace is the WSDL's target namespace */
public void assertTargetNamespace(String targetNS)
{
if (getServiceName().getNamespaceURI().equals(targetNS) == false)
throw new WSException("Requested namespace is not WSDL target namespace: " + targetNS);
}
public String toString()
{
StringBuilder buffer = new StringBuilder("\nServiceMetaData:");
buffer.append("\n qname=" + serviceName);
buffer.append("\n refName=" + serviceRefName);
buffer.append("\n wsdName=" + wsdName);
buffer.append("\n wsdlFile=" + wsdlFile);
buffer.append("\n wsdlLocation=" + wsdlLocation);
buffer.append("\n jaxrpcMapping=" + mappingLocation);
buffer.append("\n publishLocation=" + wsdlPublishLocation);
buffer.append("\n securityConfig=" + (securityConfig != null ? "found" : null));
buffer.append("\n properties=" + properties);
buffer.append("\n" + types);
buffer.append("\n");
for (EndpointMetaData epMetaData : endpoints.values())
{
buffer.append(epMetaData);
}
return buffer.toString();
}
}