/**
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.axis.builder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.wsdl.Binding;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.Port;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.xml.namespace.QName;
import org.apache.axis.constants.Style;
import org.apache.axis.constants.Use;
import org.apache.axis.description.JavaServiceDesc;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.encoding.TypeMapping;
import org.apache.axis.encoding.TypeMappingRegistryImpl;
import org.apache.geronimo.axis.client.TypeInfo;
import org.apache.geronimo.axis.server.ReadOnlyServiceDesc;
import org.apache.geronimo.axis.server.ServiceInfo;
import org.apache.geronimo.common.DeploymentException;
import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType;
import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType;
import org.apache.geronimo.xbeans.wsdl.DefinitionsDocument;
import org.apache.geronimo.xbeans.wsdl.TDefinitions;
import org.apache.geronimo.xbeans.wsdl.TImport;
import org.apache.geronimo.xbeans.wsdl.TTypes;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.xb.xsdschema.ImportDocument;
import org.apache.xmlbeans.impl.xb.xsdschema.IncludeDocument;
import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument;
/**
* @version $Rev$ $Date$
*/
public class AxisServiceBuilder {
public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
public static final QName SCHEMA_QNAME = new QName(XSD_NS, "schema");
public static ServiceInfo createServiceInfo(PortInfo portInfo, ClassLoader classLoader) throws DeploymentException {
JavaServiceDesc serviceDesc = createServiceDesc(portInfo, classLoader);
List handlerInfos = WSDescriptorParser.createHandlerInfoList(portInfo.getHandlers(), classLoader);
SchemaInfoBuilder schemaInfoBuilder = portInfo.getSchemaInfoBuilder();
Map rawWsdlMap = schemaInfoBuilder.getWsdlMap();
Map wsdlMap = rewriteWsdlMap(portInfo, rawWsdlMap);
return new ServiceInfo(serviceDesc, handlerInfos, wsdlMap);
}
public static JavaServiceDesc createServiceDesc(PortInfo portInfo, ClassLoader classLoader) throws DeploymentException {
Port port = portInfo.getPort();
Class serviceEndpointInterface = null;
try {
serviceEndpointInterface = classLoader.loadClass(portInfo.getServiceEndpointInterfaceName());
} catch (ClassNotFoundException e) {
throw (DeploymentException) new DeploymentException("Unable to load the service-endpoint interface for port-component " + portInfo.getPortComponentName()).initCause(e);
}
Map exceptionMap = WSDescriptorParser.getExceptionMap(portInfo.getJavaWsdlMapping());
SchemaInfoBuilder schemaInfoBuilder = portInfo.getSchemaInfoBuilder();
Map schemaTypeKeyToSchemaTypeMap = schemaInfoBuilder.getSchemaTypeKeyToSchemaTypeMap();
JavaServiceDesc serviceDesc = new JavaServiceDesc();
String location = getAddressLocation(port);
serviceDesc.setEndpointURL(location);
serviceDesc.setWSDLFile(portInfo.getWsdlLocation());
Binding binding = port.getBinding();
serviceDesc.setStyle(getStyle(binding));
BindingInput bindingInput = ((BindingOperation) binding.getBindingOperations().get(0)).getBindingInput();
SOAPBody soapBody = (SOAPBody) SchemaInfoBuilder.getExtensibilityElement(SOAPBody.class, bindingInput.getExtensibilityElements());
if (soapBody.getUse() != null) {
Use use = Use.getUse(soapBody.getUse());
serviceDesc.setUse(use);
} else {
serviceDesc.setUse(Use.ENCODED);
}
boolean hasEncoded = serviceDesc.getUse() == Use.ENCODED;
boolean isLightweight = portInfo.getServiceEndpointInterfaceMapping() == null;
// if (isLightweight) {
// validateLightweightMapping(portInfo.getDefinition());
// }
Collection operations = new ArrayList();
Set wrapperElementQNames = buildOperations(binding, serviceEndpointInterface, isLightweight, portInfo, exceptionMap, classLoader, operations);
for (Iterator iter = operations.iterator(); iter.hasNext();) {
OperationDesc operation = (OperationDesc) iter.next();
serviceDesc.addOperationDesc(operation);
}
TypeMappingRegistryImpl tmr = new TypeMappingRegistryImpl();
tmr.doRegisterFromVersion("1.3");
TypeMapping typeMapping = tmr.getOrMakeTypeMapping(serviceDesc.getUse().getEncoding());
serviceDesc.setTypeMappingRegistry(tmr);
serviceDesc.setTypeMapping(typeMapping);
List typeInfo;
if (isLightweight) {
LightweightTypeInfoBuilder builder = new LightweightTypeInfoBuilder(classLoader, schemaTypeKeyToSchemaTypeMap, wrapperElementQNames);
typeInfo = builder.buildTypeInfo(portInfo.getJavaWsdlMapping());
} else {
HeavyweightTypeInfoBuilder builder = new HeavyweightTypeInfoBuilder(classLoader, schemaTypeKeyToSchemaTypeMap, wrapperElementQNames, operations, hasEncoded);
typeInfo = builder.buildTypeInfo(portInfo.getJavaWsdlMapping());
}
// We register type mappings and invoke serviceDesc.getOperations to trigger an introspection of the
// operations. By doing these operations during deployment, no introspection is required during runtime.
TypeInfo.register(typeInfo, typeMapping);
serviceDesc.getOperations();
return new ReadOnlyServiceDesc(serviceDesc, typeInfo);
}
private static Set buildOperations(Binding binding, Class serviceEndpointInterface, boolean lightweight, PortInfo portInfo, Map exceptionMap, ClassLoader classLoader, Collection operations) throws DeploymentException {
Set wrappedElementQNames = new HashSet();
SOAPBinding soapBinding = (SOAPBinding) SchemaInfoBuilder.getExtensibilityElement(SOAPBinding.class, binding.getExtensibilityElements());
String portStyleString = soapBinding.getStyle();
Style portStyle = Style.getStyle(portStyleString);
List bindingOperations = binding.getBindingOperations();
for (int i = 0; i < bindingOperations.size(); i++) {
BindingOperation bindingOperation = (BindingOperation) bindingOperations.get(i);
OperationDescBuilder operationDescBuilder;
if (lightweight) {
Method method = WSDescriptorParser.getMethodForOperation(serviceEndpointInterface, bindingOperation.getOperation());
operationDescBuilder = new LightweightOperationDescBuilder(bindingOperation, method);
} else {
String operationName = bindingOperation.getOperation().getName();
ServiceEndpointMethodMappingType[] methodMappings = portInfo.getServiceEndpointInterfaceMapping().getServiceEndpointMethodMappingArray();
ServiceEndpointMethodMappingType methodMapping = WSDescriptorParser.getMethodMappingForOperation(operationName, methodMappings);
JavaXmlTypeMappingType[] javaXmlTypeMappingTypes = portInfo.getJavaWsdlMapping().getJavaXmlTypeMappingArray();
operationDescBuilder = new HeavyweightOperationDescBuilder(bindingOperation, portInfo.getJavaWsdlMapping(), methodMapping, portStyle, exceptionMap, portInfo.getSchemaInfoBuilder(), javaXmlTypeMappingTypes, classLoader, serviceEndpointInterface);
Set wrappedElementQNamesForOper = ((HeavyweightOperationDescBuilder) operationDescBuilder).getWrapperElementQNames();
wrappedElementQNames.addAll(wrappedElementQNamesForOper);
}
operations.add(operationDescBuilder.buildOperationDesc());
}
return wrappedElementQNames;
}
private static Style getStyle(Binding binding) throws DeploymentException {
SOAPBinding soapBinding = (SOAPBinding) SchemaInfoBuilder.getExtensibilityElement(SOAPBinding.class, binding.getExtensibilityElements());
String portStyleString = soapBinding.getStyle();
Style portStyle = Style.getStyle(portStyleString);
return portStyle;
}
private static String getAddressLocation(Port port) throws DeploymentException {
SOAPAddress soapAddress = (SOAPAddress) SchemaInfoBuilder.getExtensibilityElement(SOAPAddress.class, port.getExtensibilityElements());
String locationURIString = soapAddress.getLocationURI();
return locationURIString;
}
private static Map rewriteWsdlMap(PortInfo portInfo, Map rawWsdlMap) throws DeploymentException {
URI contextURI = portInfo.getContextURI();
Map wsdlMap = new HashMap();
for (Iterator iterator = rawWsdlMap.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry) iterator.next();
URI key = (URI) entry.getKey();
Object value = entry.getValue();
if (value instanceof SchemaDocument) {
SchemaDocument schemaDocument = (SchemaDocument) ((SchemaDocument) value).copy();
SchemaDocument.Schema schema = schemaDocument.getSchema();
rewriteSchema(schema, contextURI, key);
String schemaString = xmlObjectToString(schemaDocument);
wsdlMap.put(key.toString(), schemaString);
} else if (value instanceof DefinitionsDocument) {
DefinitionsDocument doc = (DefinitionsDocument) ((DefinitionsDocument) value).copy();
TDefinitions definitions = doc.getDefinitions();
TImport[] imports = definitions.getImportArray();
for (int i = 0; i < imports.length; i++) {
TImport anImport = imports[i];
String importLocation = anImport.getLocation().trim();
if (!importLocation.startsWith("http://")) {
URI updated = buildQueryURI(contextURI, key, importLocation);
anImport.setLocation(updated.toString());
}
}
TTypes[] types = definitions.getTypesArray();
for (int i = 0; i < types.length; i++) {
TTypes type = types[i];
XmlCursor typeCursor = type.newCursor();
try {
if (typeCursor.toChild(SCHEMA_QNAME)) {
do {
SchemaDocument.Schema schema = (SchemaDocument.Schema) typeCursor.getObject();
rewriteSchema(schema, contextURI, key);
} while (typeCursor.toNextSibling(SCHEMA_QNAME));
}
} finally {
typeCursor.dispose();
}
}
String docString = xmlObjectToString(doc);
wsdlMap.put(key.toString(), docString);
} else {
throw new DeploymentException("Unexpected element in wsdlMap at location: " + key + ", value: " + value);
}
}
return wsdlMap;
}
static String xmlObjectToString(XmlObject xmlObject) throws DeploymentException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
xmlObject.save(baos);
baos.flush();
String result = new String(baos.toByteArray());
return result;
} catch (IOException e) {
throw new DeploymentException("Could not write xml object to string", e);
}
}
private static void rewriteSchema(SchemaDocument.Schema schema, URI contextURI, URI key) throws DeploymentException {
ImportDocument.Import[] imports = schema.getImportArray();
for (int i = 0; i < imports.length; i++) {
ImportDocument.Import anImport = imports[i];
if (anImport.isSetSchemaLocation()) {
String schemaLocation = anImport.getSchemaLocation();
URI absoluteSchemLocation = buildQueryURI(contextURI, key, schemaLocation);
anImport.setSchemaLocation(absoluteSchemLocation.toString());
}
}
IncludeDocument.Include[] includes = schema.getIncludeArray();
for (int i = 0; i < includes.length; i++) {
IncludeDocument.Include include = includes[i];
String schemaLocation = include.getSchemaLocation();
URI absoluteSchemLocation = buildQueryURI(contextURI, key, schemaLocation);
include.setSchemaLocation(absoluteSchemLocation.toString());
}
}
private static URI buildQueryURI(URI contextURI, URI key, String importLocation) throws DeploymentException {
try {
URI importLocationURI = new URI(importLocation);
if (importLocationURI.isAbsolute() || importLocationURI.getPath().startsWith("/")) {
return importLocationURI;
}
URI queryURI = new URI(null,
null,
contextURI.getPath(),
"wsdl=" + key.resolve(importLocationURI),
null);
return queryURI;
} catch (URISyntaxException e) {
throw new DeploymentException("Could not construct wsdl location URI", e);
}
}
}