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.servicemix.common.tools.wsdl;
018    
019    import java.net.URI;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import javax.wsdl.Definition;
027    import javax.wsdl.Fault;
028    import javax.wsdl.Import;
029    import javax.wsdl.Input;
030    import javax.wsdl.Message;
031    import javax.wsdl.Operation;
032    import javax.wsdl.Output;
033    import javax.wsdl.Part;
034    import javax.wsdl.PortType;
035    import javax.wsdl.Types;
036    import javax.wsdl.extensions.ExtensibilityElement;
037    import javax.wsdl.extensions.schema.SchemaImport;
038    import javax.wsdl.factory.WSDLFactory;
039    import javax.xml.namespace.QName;
040    
041    import com.ibm.wsdl.extensions.schema.SchemaImpl;
042    
043    public class WSDLFlattener {
044    
045        private Definition definition;
046        private SchemaCollection schemas;
047        private Map<QName, Definition> flattened;
048        private boolean initialized;
049        
050        public WSDLFlattener() {
051            this(null, null);
052        }
053            
054        public WSDLFlattener(Definition definition) {
055            this(definition, null);
056        }
057            
058        public WSDLFlattener(Definition definition, SchemaCollection schemas) {
059            this.definition = definition;
060            this.flattened = new HashMap<QName, Definition>();
061            this.schemas = schemas;
062        }
063        
064        /**
065         * Parse the schemas referenced by the definition.
066         * @throws Exception if an error occurs
067         */
068        public void initialize() throws Exception {
069            if (!initialized) {
070                if (schemas == null) {
071                    this.schemas = new SchemaCollection(getUri(this.definition.getDocumentBaseURI()));
072                }
073                parseSchemas(this.definition);
074                initialized = true;
075            }
076        }
077        
078        /**
079         * Retrieve a flattened definition for a given port type name.
080         * @param portType the port type to create a flat definition for
081         * @return a flat definition for the port type
082         * @throws Exception if an error occurs
083         */
084        public Definition getDefinition(QName portType) throws Exception {
085            Definition def = flattened.get(portType);
086            if (def == null) {
087                def = flattenDefinition(portType);
088                flattened.put(portType, def);
089            }
090            return def;
091        }
092    
093        /**
094         * @return Returns the definition.
095         */
096        public Definition getDefinition() {
097            return definition;
098        }
099    
100        /**
101         * @param definition The definition to set.
102         */
103        public void setDefinition(Definition definition) {
104            this.definition = definition;
105        }
106    
107        /**
108         * @return Returns the schemas.
109         */
110        public SchemaCollection getSchemas() throws Exception {
111            return schemas;
112        }
113    
114        /**
115         * @param schemas The schemas to set.
116         */
117        public void setSchemas(SchemaCollection schemas) {
118            this.schemas = schemas;
119        }
120        
121        private Definition flattenDefinition(QName name) throws Exception {
122            // Check that schemas have been loaded
123            initialize();
124            // Create new definition
125            Definition flat = WSDLFactory.newInstance().newDefinition();
126            flat.setTargetNamespace(name.getNamespaceURI());
127            addNamespaces(flat, definition);
128            // Create port type
129            PortType defPort = definition.getPortType(name);
130            PortType flatPort = flat.createPortType();
131            flatPort.setQName(defPort.getQName());
132            flatPort.setUndefined(false);
133            // Import all operations and related messages
134            for (Iterator itOper = defPort.getOperations().iterator(); itOper.hasNext();) {
135                Operation defOper = (Operation) itOper.next();
136                Operation flatOper = flat.createOperation();
137                flatOper.setName(defOper.getName());
138                flatOper.setStyle(defOper.getStyle());
139                flatOper.setUndefined(false);
140                if (defOper.getInput() != null) {
141                    Input flatInput = flat.createInput();
142                    flatInput.setName(defOper.getInput().getName());
143                    if (defOper.getInput().getMessage() != null) {
144                        Message flatInputMsg = copyMessage(defOper.getInput().getMessage(), flat);
145                        flatInput.setMessage(flatInputMsg);
146                        flat.addMessage(flatInputMsg);
147                    }
148                    flatOper.setInput(flatInput);
149                }
150                if (defOper.getOutput() != null) {
151                    Output flatOutput = flat.createOutput();
152                    flatOutput.setName(defOper.getOutput().getName());
153                    if (defOper.getOutput().getMessage() != null) {
154                        Message flatOutputMsg = copyMessage(defOper.getOutput().getMessage(), flat);
155                        flatOutput.setMessage(flatOutputMsg);
156                        flat.addMessage(flatOutputMsg);
157                    }
158                    flatOper.setOutput(flatOutput);
159                }
160                for (Iterator itFault = defOper.getFaults().values().iterator(); itFault.hasNext();) {
161                    Fault defFault = (Fault) itFault.next();
162                    Fault flatFault = flat.createFault();
163                    flatFault.setName(defFault.getName());
164                    if (defFault.getMessage() != null) {
165                        Message flatFaultMsg = copyMessage(defFault.getMessage(), flat);
166                        flatFault.setMessage(flatFaultMsg);
167                        flat.addMessage(flatFaultMsg);
168                    }
169                    flatOper.addFault(flatFault);
170                }
171                flatPort.addOperation(flatOper);
172            }
173            
174            // Import schemas in definition
175            if (schemas.getSize() > 0) {
176               Types types = flat.createTypes();
177               for (Iterator it = schemas.getSchemas().iterator(); it.hasNext();) {
178                  javax.wsdl.extensions.schema.Schema imp = new SchemaImpl();
179                  imp.setElement(((Schema)it.next()).getRoot());
180                  imp.setElementType(new QName("http://www.w3.org/2001/XMLSchema", "schema"));
181                  types.addExtensibilityElement(imp);
182               }
183               flat.setTypes(types);
184            }
185            
186            flat.addPortType(flatPort);
187            return flat;
188        }
189        
190        private void parseSchemas(Definition def) throws Exception {
191            if (def.getTypes() != null && def.getTypes().getExtensibilityElements() != null) {
192                for (Iterator iter = def.getTypes().getExtensibilityElements().iterator(); iter.hasNext();) {
193                    ExtensibilityElement element = (ExtensibilityElement) iter.next();
194                    if (element instanceof javax.wsdl.extensions.schema.Schema) {
195                        javax.wsdl.extensions.schema.Schema schema = (javax.wsdl.extensions.schema.Schema) element;
196                        if (schema.getElement() != null) {
197                            schemas.read(schema.getElement(), getUri(schema.getDocumentBaseURI()));
198                        }
199                        for (Iterator itImp = schema.getImports().values().iterator(); itImp.hasNext();) {
200                            Collection imps = (Collection) itImp.next();
201                            for (Iterator itSi = imps.iterator(); itSi.hasNext();) {
202                                SchemaImport imp = (SchemaImport) itSi.next();
203                                schemas.read(imp.getSchemaLocationURI(), getUri(def.getDocumentBaseURI()));
204                            }
205                        }
206                    }
207                }
208            }
209            if (def.getImports() != null) {
210                for (Iterator itImp = def.getImports().values().iterator(); itImp.hasNext();) {
211                    Collection imps = (Collection) itImp.next();
212                    for (Iterator iter = imps.iterator(); iter.hasNext();) {
213                        Import imp = (Import) iter.next();
214                        parseSchemas(imp.getDefinition());
215                    }
216                }
217            }
218        }
219    
220        private void addNamespaces(Definition flat, Definition def) {
221            for (Iterator itImport = def.getImports().values().iterator(); itImport.hasNext();) {
222                List defImports = (List) itImport.next();
223                for (Iterator iter = defImports.iterator(); iter.hasNext();) {
224                    Import defImport = (Import) iter.next();
225                    addNamespaces(flat, defImport.getDefinition());
226                }
227            }
228            for (Iterator itNs = def.getNamespaces().keySet().iterator(); itNs.hasNext();) {
229                String key = (String) itNs.next();
230                String val = def.getNamespace(key);
231                flat.addNamespace(key, val);
232            }
233        }
234        
235        private Message copyMessage(Message defMessage, Definition flat) {
236            Message flatMsg = flat.createMessage();
237            flatMsg.setUndefined(false);
238            if (defMessage.getQName() != null) {
239                flatMsg.setQName(new QName(flat.getTargetNamespace(), defMessage.getQName().getLocalPart()));
240            }
241            for (Iterator itPart = defMessage.getParts().values().iterator(); itPart.hasNext();) {
242                Part defPart = (Part) itPart.next();
243                Part flatPart = flat.createPart();
244                flatPart.setName(defPart.getName());
245                flatPart.setElementName(defPart.getElementName());
246                flatMsg.addPart(flatPart);
247            }
248            return flatMsg;
249        }
250    
251        private URI getUri(String str) {
252            if (str != null) {
253                str = str.replaceAll(" ", "%20");
254                return URI.create(str);
255            }
256            return null;
257        }
258    
259    }