001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with 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,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.geronimo.axis2;
021
022 import java.io.FileNotFoundException;
023 import java.io.OutputStream;
024 import java.net.MalformedURLException;
025 import java.net.URI;
026 import java.net.URISyntaxException;
027 import java.net.URL;
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.Iterator;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.concurrent.ConcurrentHashMap;
034
035 import javax.wsdl.Definition;
036 import javax.wsdl.Import;
037 import javax.wsdl.Port;
038 import javax.wsdl.Service;
039 import javax.wsdl.Types;
040 import javax.wsdl.extensions.ExtensibilityElement;
041 import javax.wsdl.extensions.schema.Schema;
042 import javax.wsdl.extensions.schema.SchemaImport;
043 import javax.wsdl.extensions.schema.SchemaReference;
044 import javax.wsdl.extensions.soap.SOAPAddress;
045 import javax.wsdl.extensions.soap12.SOAP12Address;
046 import javax.wsdl.factory.WSDLFactory;
047 import javax.wsdl.xml.WSDLReader;
048 import javax.wsdl.xml.WSDLWriter;
049 import javax.xml.namespace.QName;
050 import javax.xml.transform.OutputKeys;
051 import javax.xml.transform.Source;
052 import javax.xml.transform.Transformer;
053 import javax.xml.transform.TransformerException;
054 import javax.xml.transform.TransformerFactory;
055 import javax.xml.transform.dom.DOMSource;
056 import javax.xml.transform.stream.StreamResult;
057
058 import org.apache.axis2.description.AxisService;
059 import org.apache.commons.logging.Log;
060 import org.apache.commons.logging.LogFactory;
061 import org.apache.geronimo.webservices.WebServiceContainer.Request;
062 import org.w3c.dom.Element;
063 import org.w3c.dom.Node;
064 import org.w3c.dom.NodeList;
065
066 public class WSDLQueryHandler {
067
068 private static final Log LOG = LogFactory.getLog(WSDLQueryHandler.class);
069
070 private Map<String, Definition> mp = new ConcurrentHashMap<String, Definition>();
071 private Map<String, SchemaReference> smp = new ConcurrentHashMap<String, SchemaReference>();
072 private AxisService service;
073
074 public WSDLQueryHandler(AxisService service) {
075 this.service = service;
076 }
077
078 public void writeResponse(String baseUri, String wsdlUri, OutputStream os) throws Exception {
079
080 String base = null;
081 String wsdl = "";
082 String xsd = null;
083
084 int idx = baseUri.toLowerCase().indexOf("?wsdl");
085 if (idx != -1) {
086 base = baseUri.substring(0, idx);
087 wsdl = baseUri.substring(idx + 5);
088 if (wsdl.length() > 0) {
089 wsdl = wsdl.substring(1);
090 }
091 } else {
092 idx = baseUri.toLowerCase().indexOf("?xsd");
093 if (idx != -1) {
094 base = baseUri.substring(0, idx);
095 xsd = baseUri.substring(idx + 4);
096 if (xsd.length() > 0) {
097 xsd = xsd.substring(1);
098 }
099 } else {
100 throw new Exception("Invalid request: " + baseUri);
101 }
102 }
103
104 if (!mp.containsKey(wsdl)) {
105 WSDLFactory factory = WSDLFactory.newInstance();
106 WSDLReader reader = factory.newWSDLReader();
107 reader.setFeature("javax.wsdl.importDocuments", true);
108 reader.setFeature("javax.wsdl.verbose", false);
109 Definition def = reader.readWSDL(wsdlUri);
110 updateDefinition(def, mp, smp, base);
111 updateServices(this.service.getName(), this.service.getEndpointName(), def, base);
112 mp.put("", def);
113 }
114
115 Element rootElement;
116
117 if (xsd == null) {
118 Definition def = mp.get(wsdl);
119
120 if (def == null) {
121 throw new FileNotFoundException("WSDL not found: " + wsdl);
122 }
123
124 WSDLFactory factory = WSDLFactory.newInstance();
125 WSDLWriter writer = factory.newWSDLWriter();
126
127 rootElement = writer.getDocument(def).getDocumentElement();
128 } else {
129 SchemaReference si = smp.get(xsd);
130
131 if (si == null) {
132 throw new FileNotFoundException("Schema not found: " + xsd);
133 }
134
135 rootElement = si.getReferencedSchema().getElement();
136 }
137
138 NodeList nl = rootElement.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema",
139 "import");
140 for (int x = 0; x < nl.getLength(); x++) {
141 Element el = (Element) nl.item(x);
142 String sl = el.getAttribute("schemaLocation");
143 if (smp.containsKey(sl)) {
144 el.setAttribute("schemaLocation", base + "?xsd=" + sl);
145 }
146 }
147 nl = rootElement.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "include");
148 for (int x = 0; x < nl.getLength(); x++) {
149 Element el = (Element) nl.item(x);
150 String sl = el.getAttribute("schemaLocation");
151 if (smp.containsKey(sl)) {
152 el.setAttribute("schemaLocation", base + "?xsd=" + sl);
153 }
154 }
155 nl = rootElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "import");
156 for (int x = 0; x < nl.getLength(); x++) {
157 Element el = (Element) nl.item(x);
158 String sl = el.getAttribute("location");
159 if (mp.containsKey(sl)) {
160 el.setAttribute("location", base + "?wsdl=" + sl);
161 }
162 }
163
164 writeTo(rootElement, os);
165 }
166
167 protected void updateDefinition(Definition def,
168 Map<String, Definition> done,
169 Map<String, SchemaReference> doneSchemas,
170 String base) {
171 Collection<List> imports = def.getImports().values();
172 for (List lst : imports) {
173 List<Import> impLst = lst;
174 for (Import imp : impLst) {
175 String start = imp.getLocationURI();
176 try {
177 //check to see if it's aleady in a URL format. If so, leave it.
178 new URL(start);
179 } catch (MalformedURLException e) {
180 done.put(start, imp.getDefinition());
181 updateDefinition(imp.getDefinition(), done, doneSchemas, base);
182 }
183 }
184 }
185
186
187 /* This doesn't actually work. Setting setSchemaLocationURI on the import
188 * for some reason doesn't actually result in the new URI being written
189 * */
190 Types types = def.getTypes();
191 if (types != null) {
192 for (ExtensibilityElement el : (List<ExtensibilityElement>)types.getExtensibilityElements()) {
193 if (el instanceof Schema) {
194 Schema see = (Schema)el;
195 updateSchemaImports(see, doneSchemas, base);
196 }
197 }
198 }
199 }
200
201 protected void updateSchemaImports(Schema schema,
202 Map<String, SchemaReference> doneSchemas,
203 String base) {
204 Collection<List> imports = schema.getImports().values();
205 for (List lst : imports) {
206 List<SchemaImport> impLst = lst;
207 for (SchemaImport imp : impLst) {
208 String start = imp.getSchemaLocationURI();
209 if (start != null) {
210 try {
211 //check to see if it's aleady in a URL format. If so, leave it.
212 new URL(start);
213 } catch (MalformedURLException e) {
214 if (!doneSchemas.containsKey(start)) {
215 doneSchemas.put(start, imp);
216 updateSchemaImports(imp.getReferencedSchema(), doneSchemas, base);
217 }
218 }
219 }
220 }
221 }
222 List<SchemaReference> includes = schema.getIncludes();
223 for (SchemaReference included : includes) {
224 String start = included.getSchemaLocationURI();
225 if (start != null) {
226 try {
227 //check to see if it's aleady in a URL format. If so, leave it.
228 new URL(start);
229 } catch (MalformedURLException e) {
230 if (!doneSchemas.containsKey(start)) {
231 doneSchemas.put(start, included);
232 updateSchemaImports(included.getReferencedSchema(), doneSchemas, base);
233 }
234 }
235 }
236 }
237 }
238
239 public static void writeTo(Node node, OutputStream os) {
240 writeTo(new DOMSource(node), os);
241 }
242
243 public static void writeTo(Source src, OutputStream os) {
244 Transformer it;
245 try {
246 it = TransformerFactory.newInstance().newTransformer();
247 it.setOutputProperty(OutputKeys.METHOD, "xml");
248 it.setOutputProperty(OutputKeys.INDENT, "yes");
249 it.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
250 it.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "false");
251 it.setOutputProperty(OutputKeys.ENCODING, "utf-8");
252 it.transform(src, new StreamResult(os));
253 } catch (TransformerException e) {
254 // TODO Auto-generated catch block
255 e.printStackTrace();
256 }
257 }
258
259 private void updateServices(String serviceName, String portName, Definition def, String baseUri)
260 throws Exception {
261 boolean updated = false;
262 Map services = def.getServices();
263 if (services != null) {
264 ArrayList<QName> servicesToRemove = new ArrayList<QName>();
265
266 Iterator serviceIterator = services.entrySet().iterator();
267 while (serviceIterator.hasNext()) {
268 Map.Entry serviceEntry = (Map.Entry) serviceIterator.next();
269 QName currServiceName = (QName) serviceEntry.getKey();
270 if (currServiceName.getLocalPart().equals(serviceName)) {
271 Service service = (Service) serviceEntry.getValue();
272 updatePorts(portName, service, baseUri);
273 updated = true;
274 } else {
275 servicesToRemove.add(currServiceName);
276 }
277 }
278
279 for (QName serviceToRemove : servicesToRemove) {
280 def.removeService(serviceToRemove);
281 }
282 }
283 if (!updated) {
284 LOG.warn("WSDL '" + serviceName + "' service not found.");
285 }
286 }
287
288 private void updatePorts(String portName, Service service, String baseUri) throws Exception {
289 boolean updated = false;
290 Map ports = service.getPorts();
291 if (ports != null) {
292 ArrayList<String> portsToRemove = new ArrayList<String>();
293
294 Iterator portIterator = ports.entrySet().iterator();
295 while (portIterator.hasNext()) {
296 Map.Entry portEntry = (Map.Entry) portIterator.next();
297 String currPortName = (String) portEntry.getKey();
298 if (currPortName.equals(portName)) {
299 Port port = (Port) portEntry.getValue();
300 updatePortLocation(port, baseUri);
301 updated = true;
302 } else {
303 portsToRemove.add(currPortName);
304 }
305 }
306
307 for (String portToRemove : portsToRemove) {
308 service.removePort(portToRemove);
309 }
310 }
311 if (!updated) {
312 LOG.warn("WSDL '" + portName + "' port not found.");
313 }
314 }
315
316 private void updatePortLocation(Port port, String baseUri) throws URISyntaxException {
317 List<?> exts = port.getExtensibilityElements();
318 if (exts != null && exts.size() > 0) {
319 ExtensibilityElement el = (ExtensibilityElement) exts.get(0);
320 if (el instanceof SOAP12Address) {
321 SOAP12Address add = (SOAP12Address) el;
322 add.setLocationURI(baseUri);
323 } else if (el instanceof SOAPAddress) {
324 SOAPAddress add = (SOAPAddress) el;
325 add.setLocationURI(baseUri);
326 }
327 }
328 }
329 }