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