View Javadoc

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