View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.support.wsdl;
14  
15  import com.eviware.soapui.config.DefinitionCacheConfig;
16  import com.eviware.soapui.config.DefinitionCacheTypeConfig;
17  import com.eviware.soapui.config.DefintionPartConfig;
18  import com.eviware.soapui.impl.support.AbstractInterface;
19  import com.eviware.soapui.impl.wsdl.support.Constants;
20  import com.eviware.soapui.impl.wsdl.support.PathUtils;
21  import com.eviware.soapui.support.Tools;
22  import com.eviware.soapui.support.types.StringToStringMap;
23  import com.eviware.soapui.support.xml.XmlUtils;
24  import org.apache.xmlbeans.SimpleValue;
25  import org.apache.xmlbeans.XmlException;
26  import org.apache.xmlbeans.XmlObject;
27  import org.apache.xmlbeans.XmlOptions;
28  import org.w3c.dom.Node;
29  
30  import java.io.File;
31  import java.io.InputStream;
32  import java.net.MalformedURLException;
33  import java.net.URL;
34  import java.util.HashMap;
35  import java.util.List;
36  import java.util.Map;
37  
38  /***
39   * WsdlLoader for cached definitions
40   *
41   * @author ole.matzura
42   */
43  
44  public class CachedWsdlLoader extends WsdlLoader
45  {
46     private final DefinitionCacheConfig config;
47     private String rootInConfig = "";
48  
49     public CachedWsdlLoader(DefinitionCacheConfig config)
50     {
51        super(config.getRootPart());
52        this.config = config;
53     }
54  
55     public CachedWsdlLoader(AbstractInterface iface) throws Exception
56     {
57        this(WsdlUtils.cacheWsdl(new UrlWsdlLoader(PathUtils.expandPath(iface.getDefinition(), iface), iface)));
58     }
59  
60     public InputStream load(String url) throws Exception
61     {
62        XmlObject xmlObject = loadXmlObject(url, null);
63        return xmlObject == null ? null : xmlObject.newInputStream();
64     }
65  
66     public XmlObject loadXmlObject(String url, XmlOptions options) throws Exception
67     {
68        // required for backwards compatibility when the entire path was stored
69        if (url.endsWith(config.getRootPart()))
70        {
71           rootInConfig = url.substring(0, url.length() - config.getRootPart().length());
72        }
73  
74        List<DefintionPartConfig> partList = config.getPartList();
75        for (DefintionPartConfig part : partList)
76        {
77           if ((rootInConfig + part.getUrl()).equalsIgnoreCase(url))
78           {
79              return getPartContent(config, part);
80           }
81        }
82  
83        // hack: this could be due to windows -> unix, try again with replaced '/'
84        if (File.separatorChar == '/')
85        {
86           url = url.replace('/', '//');
87  
88           for (DefintionPartConfig part : partList)
89           {
90              if ((rootInConfig + part.getUrl()).equalsIgnoreCase(url))
91              {
92                 return getPartContent(config, part);
93              }
94           }
95        }
96        // or the other way around..
97        else if (File.separatorChar == '//')
98        {
99           url = url.replace('//', '/');
100 
101          for (DefintionPartConfig part : partList)
102          {
103             if ((rootInConfig + part.getUrl()).equalsIgnoreCase(url))
104             {
105                return getPartContent(config, part);
106             }
107          }
108       }
109 
110       return null;
111    }
112 
113    public static XmlObject getPartContent(DefinitionCacheConfig config, DefintionPartConfig part) throws XmlException
114    {
115       if (config.getType() == DefinitionCacheTypeConfig.TEXT)
116       {
117          Node domNode = part.getContent().getDomNode();
118          String nodeValue = XmlUtils.getNodeValue(domNode);
119          return XmlObject.Factory.parse(nodeValue, new XmlOptions().setLoadLineNumbers());
120       }
121 
122       return XmlObject.Factory.parse(part.getContent().toString(), new XmlOptions().setLoadLineNumbers());
123    }
124 
125    /***
126     * Saves the complete definition to the specified folder, returns path to root part
127     *
128     * @param folderName
129     * @return
130     * @throws Exception
131     */
132 
133    public String saveDefinition(String folderName) throws Exception
134    {
135       File outFolder = new File(folderName);
136       if (!outFolder.exists() && !outFolder.mkdirs())
137          throw new Exception("Failed to create directory [" + folderName + "]");
138 
139       Map<String, String> urlToFileMap = new HashMap<String, String>();
140 
141       setFilenameForUrl(config.getRootPart(), Constants.WSDL11_NS, urlToFileMap, null);
142 
143       List<DefintionPartConfig> partList = config.getPartList();
144       for (DefintionPartConfig part : partList)
145       {
146          setFilenameForUrl(part.getUrl(), part.getType(), urlToFileMap, null);
147       }
148 
149       for (DefintionPartConfig part : partList)
150       {
151          XmlObject obj = null;
152          if (config.getType() == DefinitionCacheTypeConfig.TEXT)
153          {
154             obj = XmlObject.Factory.parse(XmlUtils.getNodeValue(part.getContent().getDomNode()));
155          }
156          else
157          {
158             obj = XmlObject.Factory.parse(part.getContent().toString());
159          }
160 
161          replaceImportsAndIncludes(obj, urlToFileMap, part.getUrl());
162          obj.save(new File(outFolder, urlToFileMap.get(part.getUrl())));
163       }
164 
165       return folderName + File.separatorChar + urlToFileMap.get(config.getRootPart());
166    }
167 
168    public StringToStringMap createFilesForExport(String urlPrefix) throws Exception
169    {
170       StringToStringMap result = new StringToStringMap();
171       Map<String, String> urlToFileMap = new HashMap<String, String>();
172 
173       if (urlPrefix == null)
174          urlPrefix = "";
175 
176       setFilenameForUrl(config.getRootPart(), Constants.WSDL11_NS, urlToFileMap, urlPrefix);
177 
178       List<DefintionPartConfig> partList = config.getPartList();
179       for (DefintionPartConfig part : partList)
180       {
181          if (!part.getUrl().equals(config.getRootPart()))
182             setFilenameForUrl(part.getUrl(), part.getType(), urlToFileMap, urlPrefix);
183       }
184 
185       for (DefintionPartConfig part : partList)
186       {
187          XmlObject obj = CachedWsdlLoader.getPartContent(config, part);
188          replaceImportsAndIncludes(obj, urlToFileMap, part.getUrl());
189          String urlString = urlToFileMap.get(part.getUrl());
190          if (urlString.startsWith(urlPrefix))
191             urlString = urlString.substring(urlPrefix.length());
192 
193          result.put(urlString, obj.xmlText());
194 
195          if (part.getUrl().equals(config.getRootPart()))
196             result.put("#root#", obj.xmlText());
197       }
198 
199       return result;
200    }
201 
202    private void setFilenameForUrl(String fileUrl, String type, Map<String, String> urlToFileMap, String urlPrefix)
203            throws MalformedURLException
204    {
205 
206       String path = fileUrl;
207 
208       try
209       {
210          URL url = new URL(fileUrl);
211          path = url.getPath();
212       }
213       catch (MalformedURLException e)
214       {
215       }
216 
217       int ix = path.lastIndexOf('/');
218       String fileName = ix == -1 ? path : path.substring(ix + 1);
219 
220       ix = fileName.lastIndexOf('.');
221       if (ix != -1)
222          fileName = fileName.substring(0, ix);
223 
224       if (type.equals(Constants.WSDL11_NS))
225          fileName += ".wsdl";
226       else if (type.equals(Constants.XSD_NS))
227          fileName += ".xsd";
228       else
229          fileName += ".xml";
230 
231       if (urlPrefix != null)
232          fileName = urlPrefix + fileName;
233 
234       int cnt = 1;
235       while (urlToFileMap.containsValue(fileName))
236       {
237          ix = fileName.lastIndexOf('.');
238          fileName = fileName.substring(0, ix) + "_" + cnt + fileName.substring(ix);
239          cnt++;
240       }
241 
242       urlToFileMap.put(fileUrl, fileName);
243    }
244 
245    private void replaceImportsAndIncludes(XmlObject xmlObject, Map<String, String> urlToFileMap, String baseUrl)
246            throws Exception
247    {
248       XmlObject[] wsdlImports = xmlObject
249               .selectPath("declare namespace s='http://schemas.xmlsoap.org/wsdl/' .//s:import/@location");
250 
251       for (int i = 0; i < wsdlImports.length; i++)
252       {
253          SimpleValue wsdlImport = ((SimpleValue) wsdlImports[i]);
254          replaceLocation(urlToFileMap, baseUrl, wsdlImport);
255       }
256 
257       XmlObject[] schemaImports = xmlObject
258               .selectPath("declare namespace s='http://www.w3.org/2001/XMLSchema' .//s:import/@schemaLocation");
259 
260       for (int i = 0; i < schemaImports.length; i++)
261       {
262          SimpleValue schemaImport = ((SimpleValue) schemaImports[i]);
263          replaceLocation(urlToFileMap, baseUrl, schemaImport);
264       }
265 
266       XmlObject[] schemaIncludes = xmlObject
267               .selectPath("declare namespace s='http://www.w3.org/2001/XMLSchema' .//s:include/@schemaLocation");
268       for (int i = 0; i < schemaIncludes.length; i++)
269       {
270          SimpleValue schemaInclude = ((SimpleValue) schemaIncludes[i]);
271          replaceLocation(urlToFileMap, baseUrl, schemaInclude);
272       }
273 
274 
275       XmlObject[] wadlImports = xmlObject
276               .selectPath("declare namespace s='" + Constants.WADL10_NS + "' .//s:grammars/s:include/@href");
277 
278       for (int i = 0; i < wadlImports.length; i++)
279       {
280          SimpleValue wadlImport = ((SimpleValue) wadlImports[i]);
281          replaceLocation(urlToFileMap, baseUrl, wadlImport);
282       }
283    }
284 
285    private void replaceLocation(Map<String, String> urlToFileMap, String baseUrl, SimpleValue wsdlImport)
286            throws Exception
287    {
288       String location = wsdlImport.getStringValue();
289       if (location != null)
290       {
291          if (location.startsWith("file:") || location.indexOf("://") > 0)
292          {
293             String newLocation = urlToFileMap.get(location);
294             if (newLocation != null)
295                wsdlImport.setStringValue(newLocation);
296             else
297                throw new Exception("Missing local file for [" + newLocation + "]");
298          }
299          else
300          {
301             String loc = Tools.joinRelativeUrl(baseUrl, location);
302             String newLocation = urlToFileMap.get(loc);
303             if (newLocation != null)
304                wsdlImport.setStringValue(newLocation);
305             else
306                throw new Exception("Missing local file for [" + loc + "]");
307          }
308       }
309    }
310 
311    public void close()
312 	{
313 	}
314 }