001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.axis.builder;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    import java.lang.reflect.Method;
023    import java.net.URI;
024    import java.net.URISyntaxException;
025    import java.util.ArrayList;
026    import java.util.Collection;
027    import java.util.HashMap;
028    import java.util.HashSet;
029    import java.util.Iterator;
030    import java.util.List;
031    import java.util.Map;
032    import java.util.Set;
033    import javax.wsdl.Binding;
034    import javax.wsdl.BindingInput;
035    import javax.wsdl.BindingOperation;
036    import javax.wsdl.Port;
037    import javax.wsdl.extensions.soap.SOAPAddress;
038    import javax.wsdl.extensions.soap.SOAPBinding;
039    import javax.wsdl.extensions.soap.SOAPBody;
040    import javax.xml.namespace.QName;
041    
042    import org.apache.axis.constants.Style;
043    import org.apache.axis.constants.Use;
044    import org.apache.axis.description.JavaServiceDesc;
045    import org.apache.axis.description.OperationDesc;
046    import org.apache.axis.encoding.TypeMapping;
047    import org.apache.axis.encoding.TypeMappingRegistryImpl;
048    import org.apache.geronimo.axis.client.TypeInfo;
049    import org.apache.geronimo.axis.server.ReadOnlyServiceDesc;
050    import org.apache.geronimo.axis.server.ServiceInfo;
051    import org.apache.geronimo.common.DeploymentException;
052    import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType;
053    import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType;
054    import org.apache.geronimo.xbeans.wsdl.DefinitionsDocument;
055    import org.apache.geronimo.xbeans.wsdl.TDefinitions;
056    import org.apache.geronimo.xbeans.wsdl.TImport;
057    import org.apache.geronimo.xbeans.wsdl.TTypes;
058    import org.apache.geronimo.webservices.builder.PortInfo;
059    import org.apache.geronimo.webservices.builder.SchemaInfoBuilder;
060    import org.apache.geronimo.webservices.builder.WSDescriptorParser;
061    import org.apache.xmlbeans.XmlCursor;
062    import org.apache.xmlbeans.XmlObject;
063    import org.apache.xmlbeans.impl.xb.xsdschema.ImportDocument;
064    import org.apache.xmlbeans.impl.xb.xsdschema.IncludeDocument;
065    import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument;
066    
067    /**
068     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
069     */
070    public class AxisServiceBuilder {
071    
072        public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
073        public static final QName SCHEMA_QNAME = new QName(XSD_NS, "schema");
074    
075    
076        public static ServiceInfo createServiceInfo(PortInfo portInfo, ClassLoader classLoader) throws DeploymentException {
077            JavaServiceDesc serviceDesc = createServiceDesc(portInfo, classLoader);
078            List handlerInfos = WSDescriptorParser.createHandlerInfoList(portInfo.getHandlers(), classLoader);
079            SchemaInfoBuilder schemaInfoBuilder = portInfo.getSchemaInfoBuilder();
080            Map rawWsdlMap = schemaInfoBuilder.getWsdlMap();
081            Map wsdlMap = rewriteWsdlMap(portInfo, rawWsdlMap);
082            return new ServiceInfo(serviceDesc, handlerInfos, wsdlMap);
083        }
084    
085        public static JavaServiceDesc createServiceDesc(PortInfo portInfo, ClassLoader classLoader) throws DeploymentException {
086    
087            Port port = portInfo.getPort();
088    
089            Class serviceEndpointInterface = null;
090            try {
091                serviceEndpointInterface = classLoader.loadClass(portInfo.getServiceEndpointInterfaceName());
092            } catch (ClassNotFoundException e) {
093                throw (DeploymentException) new DeploymentException("Unable to load the service-endpoint interface for port-component " + portInfo.getPortComponentName()).initCause(e);
094            }
095    
096            Map exceptionMap = WSDescriptorParser.getExceptionMap(portInfo.getJavaWsdlMapping());
097            SchemaInfoBuilder schemaInfoBuilder = portInfo.getSchemaInfoBuilder();
098            Map schemaTypeKeyToSchemaTypeMap = schemaInfoBuilder.getSchemaTypeKeyToSchemaTypeMap();
099    
100            JavaServiceDesc serviceDesc = new JavaServiceDesc();
101            String serviceName =  portInfo.getPortQName().toString();
102            String location = getAddressLocation(port);
103            serviceDesc.setName(serviceName);
104            serviceDesc.setEndpointURL(location);
105            serviceDesc.setWSDLFile(portInfo.getWsdlLocation());
106            Binding binding = port.getBinding();
107    
108            serviceDesc.setStyle(getStyle(binding));
109    
110    
111            BindingInput bindingInput = ((BindingOperation) binding.getBindingOperations().get(0)).getBindingInput();
112            SOAPBody soapBody = (SOAPBody) SchemaInfoBuilder.getExtensibilityElement(SOAPBody.class, bindingInput.getExtensibilityElements());
113    
114            if (soapBody.getUse() != null) {
115                Use use = Use.getUse(soapBody.getUse());
116                serviceDesc.setUse(use);
117            } else {
118                serviceDesc.setUse(Use.ENCODED);
119            }
120            boolean hasEncoded = serviceDesc.getUse() == Use.ENCODED;
121    
122            boolean isLightweight = portInfo.getServiceEndpointInterfaceMapping() == null;
123    
124    //        if (isLightweight) {
125    //            validateLightweightMapping(portInfo.getDefinition());
126    //        }
127    
128            Collection operations = new ArrayList();
129            Set wrapperElementQNames = buildOperations(binding, serviceEndpointInterface, isLightweight, portInfo, exceptionMap, classLoader, operations);
130            for (Iterator iter = operations.iterator(); iter.hasNext();) {
131                OperationDesc operation = (OperationDesc) iter.next();
132                serviceDesc.addOperationDesc(operation);
133            }
134    
135            TypeMappingRegistryImpl tmr = new TypeMappingRegistryImpl();
136            tmr.doRegisterFromVersion("1.3");
137    
138            TypeMapping typeMapping = tmr.getOrMakeTypeMapping(serviceDesc.getUse().getEncoding());
139    
140            serviceDesc.setTypeMappingRegistry(tmr);
141            serviceDesc.setTypeMapping(typeMapping);
142    
143            List typeInfo;
144            if (isLightweight) {
145                LightweightTypeInfoBuilder builder = new LightweightTypeInfoBuilder(classLoader, schemaTypeKeyToSchemaTypeMap, wrapperElementQNames);
146                typeInfo = builder.buildTypeInfo(portInfo.getJavaWsdlMapping());
147            } else {
148                HeavyweightTypeInfoBuilder builder = new HeavyweightTypeInfoBuilder(classLoader, schemaTypeKeyToSchemaTypeMap, wrapperElementQNames, operations, hasEncoded);
149                typeInfo = builder.buildTypeInfo(portInfo.getJavaWsdlMapping());
150            }
151    
152            // We register type mappings and invoke serviceDesc.getOperations to trigger an introspection of the
153            // operations. By doing these operations during deployment, no introspection is required during runtime.
154            TypeInfo.register(typeInfo, typeMapping);
155            serviceDesc.getOperations();
156    
157            return new ReadOnlyServiceDesc(serviceDesc, typeInfo);
158        }
159    
160        private static Set buildOperations(Binding binding, Class serviceEndpointInterface, boolean lightweight, PortInfo portInfo, Map exceptionMap, ClassLoader classLoader, Collection operations) throws DeploymentException {
161            Set wrappedElementQNames = new HashSet();
162    
163            SOAPBinding soapBinding = (SOAPBinding) SchemaInfoBuilder.getExtensibilityElement(SOAPBinding.class, binding.getExtensibilityElements());
164            String portStyleString = soapBinding.getStyle();
165            Style portStyle = Style.getStyle(portStyleString);
166    
167            List bindingOperations = binding.getBindingOperations();
168            for (int i = 0; i < bindingOperations.size(); i++) {
169                BindingOperation bindingOperation = (BindingOperation) bindingOperations.get(i);
170    
171                OperationDescBuilder operationDescBuilder;
172                if (lightweight) {
173                    Method method = WSDescriptorParser.getMethodForOperation(serviceEndpointInterface, bindingOperation.getOperation());
174                    operationDescBuilder = new LightweightOperationDescBuilder(bindingOperation, method);
175                } else {
176                    String operationName = bindingOperation.getOperation().getName();
177                    ServiceEndpointMethodMappingType[] methodMappings = portInfo.getServiceEndpointInterfaceMapping().getServiceEndpointMethodMappingArray();
178                    ServiceEndpointMethodMappingType methodMapping = WSDescriptorParser.getMethodMappingForOperation(operationName, methodMappings);
179                    JavaXmlTypeMappingType[] javaXmlTypeMappingTypes = portInfo.getJavaWsdlMapping().getJavaXmlTypeMappingArray();
180                    operationDescBuilder = new HeavyweightOperationDescBuilder(bindingOperation, portInfo.getJavaWsdlMapping(), methodMapping, portStyle, exceptionMap, portInfo.getSchemaInfoBuilder(), javaXmlTypeMappingTypes, classLoader, serviceEndpointInterface);
181                    Set wrappedElementQNamesForOper = ((HeavyweightOperationDescBuilder) operationDescBuilder).getWrapperElementQNames();
182                    wrappedElementQNames.addAll(wrappedElementQNamesForOper);
183                }
184    
185                operations.add(operationDescBuilder.buildOperationDesc());
186            }
187    
188            return wrappedElementQNames;
189        }
190    
191    
192        private static Style getStyle(Binding binding) throws DeploymentException {
193            SOAPBinding soapBinding = (SOAPBinding) SchemaInfoBuilder.getExtensibilityElement(SOAPBinding.class, binding.getExtensibilityElements());
194            String portStyleString = soapBinding.getStyle();
195            Style portStyle = Style.getStyle(portStyleString);
196            return portStyle;
197        }
198    
199        private static String getAddressLocation(Port port) throws DeploymentException {
200            SOAPAddress soapAddress = (SOAPAddress) SchemaInfoBuilder.getExtensibilityElement(SOAPAddress.class, port.getExtensibilityElements());
201            String locationURIString = soapAddress.getLocationURI();
202            return locationURIString;
203        }
204    
205        private static Map rewriteWsdlMap(PortInfo portInfo, Map rawWsdlMap) throws DeploymentException {
206            URI contextURI = portInfo.getContextURI();
207            Map wsdlMap = new HashMap();
208            for (Iterator iterator = rawWsdlMap.entrySet().iterator(); iterator.hasNext();) {
209                Map.Entry entry = (Map.Entry) iterator.next();
210                URI key = (URI) entry.getKey();
211                Object value = entry.getValue();
212                if (value instanceof SchemaDocument) {
213                    SchemaDocument schemaDocument = (SchemaDocument) ((SchemaDocument) value).copy();
214                    SchemaDocument.Schema schema = schemaDocument.getSchema();
215                    rewriteSchema(schema, contextURI, key);
216                    String schemaString = xmlObjectToString(schemaDocument);
217                    wsdlMap.put(key.toString(), schemaString);
218                } else if (value instanceof DefinitionsDocument) {
219                    DefinitionsDocument doc = (DefinitionsDocument) ((DefinitionsDocument) value).copy();
220                    TDefinitions definitions = doc.getDefinitions();
221                    TImport[] imports = definitions.getImportArray();
222                    for (int i = 0; i < imports.length; i++) {
223                        TImport anImport = imports[i];
224                        String importLocation = anImport.getLocation().trim();
225                        if (!importLocation.startsWith("http://")) {
226                            URI updated = buildQueryURI(contextURI, key, importLocation);
227                            anImport.setLocation(updated.toString());
228                        }
229                    }
230                    TTypes[] types = definitions.getTypesArray();
231                    for (int i = 0; i < types.length; i++) {
232                        TTypes type = types[i];
233                        XmlCursor typeCursor = type.newCursor();
234                        try {
235                            if (typeCursor.toChild(SCHEMA_QNAME)) {
236                                do {
237                                    SchemaDocument.Schema schema = (SchemaDocument.Schema) typeCursor.getObject();
238                                    rewriteSchema(schema, contextURI, key);
239                                } while (typeCursor.toNextSibling(SCHEMA_QNAME));
240                            }
241                        } finally {
242                            typeCursor.dispose();
243                        }
244                    }
245                    String docString = xmlObjectToString(doc);
246                    wsdlMap.put(key.toString(), docString);
247                } else {
248                    throw new DeploymentException("Unexpected element in wsdlMap at location: " + key + ", value: " + value);
249                }
250            }
251            return wsdlMap;
252        }
253    
254        static String xmlObjectToString(XmlObject xmlObject) throws DeploymentException {
255            ByteArrayOutputStream baos = new ByteArrayOutputStream();
256            try {
257                xmlObject.save(baos);
258                baos.flush();
259                String result = new String(baos.toByteArray());
260                return result;
261            } catch (IOException e) {
262                throw new DeploymentException("Could not write xml object to string", e);
263            }
264        }
265    
266        private static void rewriteSchema(SchemaDocument.Schema schema, URI contextURI, URI key) throws DeploymentException {
267            ImportDocument.Import[] imports = schema.getImportArray();
268            for (int i = 0; i < imports.length; i++) {
269                ImportDocument.Import anImport = imports[i];
270                if (anImport.isSetSchemaLocation()) {
271                    String schemaLocation = anImport.getSchemaLocation();
272                    URI absoluteSchemLocation = buildQueryURI(contextURI, key, schemaLocation);
273                    anImport.setSchemaLocation(absoluteSchemLocation.toString());
274                }
275            }
276            IncludeDocument.Include[] includes = schema.getIncludeArray();
277            for (int i = 0; i < includes.length; i++) {
278                IncludeDocument.Include include = includes[i];
279                String schemaLocation = include.getSchemaLocation();
280                URI absoluteSchemLocation = buildQueryURI(contextURI, key, schemaLocation);
281                include.setSchemaLocation(absoluteSchemLocation.toString());
282            }
283        }
284    
285        private static URI buildQueryURI(URI contextURI, URI key, String importLocation) throws DeploymentException {
286            try {
287                URI importLocationURI = new URI(importLocation);
288                if (importLocationURI.isAbsolute() || importLocationURI.getPath().startsWith("/")) {
289                    return importLocationURI;
290                }
291                URI queryURI = new URI(null,
292                        null,
293                        contextURI.getPath(),
294                        "wsdl=" + key.resolve(importLocationURI),
295                        null);
296                return queryURI;
297            } catch (URISyntaxException e) {
298                throw new DeploymentException("Could not construct wsdl location URI", e);
299            }
300        }
301    
302    
303    }