View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.commons.httpclient.HttpState;
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 com.eviware.soapui.config.DefinitionCacheConfig;
31  import com.eviware.soapui.config.DefinitionCacheTypeConfig;
32  import com.eviware.soapui.config.DefintionPartConfig;
33  import com.eviware.soapui.impl.wsdl.support.Constants;
34  import com.eviware.soapui.support.Tools;
35  import com.eviware.soapui.support.types.StringToStringMap;
36  import com.eviware.soapui.support.xml.XmlUtils;
37  
38  /***
39   * WsdlLoader for cached definitions
40   * 
41   * @author ole.matzura
42   */
43  
44  public class CachedWsdlLoader extends WsdlLoader
45  {
46  	@SuppressWarnings( "unused" )
47  	private HttpState state;
48  	private final DefinitionCacheConfig config;
49  
50  	public CachedWsdlLoader( DefinitionCacheConfig config )
51  	{
52  		super( config.getRootPart() );
53  		this.config = config;
54  	}
55  
56  	public CachedWsdlLoader( String wsdlUrl ) throws Exception
57  	{
58  		this( WsdlLoader.cacheWsdl( new UrlWsdlLoader( wsdlUrl ) ) );
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  		List<DefintionPartConfig> partList = config.getPartList();
70  		for( DefintionPartConfig part : partList )
71  		{
72  			if( part.getUrl().equalsIgnoreCase( url ) )
73  			{
74  				return getPartContent( config, part );
75  			}
76  		}
77  
78  		// hack: this could be due to windows -> unix, try again with replaced '/'
79  		if( File.separatorChar == '/' )
80  		{
81  			url = url.replace( '/', '//' );
82  
83  			for( DefintionPartConfig part : partList )
84  			{
85  				if( part.getUrl().equalsIgnoreCase( url ) )
86  				{
87  					return getPartContent( config, part );
88  				}
89  			}
90  		}
91  		// or the other way around..
92  		else if( File.separatorChar == '//' )
93  		{
94  			url = url.replace( '//', '/' );
95  
96  			for( DefintionPartConfig part : partList )
97  			{
98  				if( part.getUrl().equalsIgnoreCase( url ) )
99  				{
100 					return getPartContent( config, part );
101 				}
102 			}
103 		}
104 
105 		return null;
106 	}
107 
108 	public static XmlObject getPartContent( DefinitionCacheConfig config, DefintionPartConfig part ) throws XmlException
109 	{
110 		if( config.getType() == DefinitionCacheTypeConfig.TEXT )
111 		{
112 			Node domNode = part.getContent().getDomNode();
113 			String nodeValue = XmlUtils.getNodeValue( domNode );
114 			return XmlObject.Factory.parse( nodeValue, new XmlOptions().setLoadLineNumbers() );
115 		}
116 			
117 		return XmlObject.Factory.parse( part.getContent().toString(), new XmlOptions().setLoadLineNumbers() );
118 	}
119 
120 	public boolean abort()
121 	{
122 		return false;
123 	}
124 
125 	public boolean isAborted()
126 	{
127 		return false;
128 	}
129 
130 	public String saveDefinition( String folderName ) throws Exception
131 	{
132 		File outFolder = new File( folderName );
133 		if( !outFolder.exists() && !outFolder.mkdirs() )
134 			throw new Exception( "Failed to create directory [" + folderName + "]" );
135 
136 		Map<String, String> urlToFileMap = new HashMap<String, String>();
137 
138 		setFilenameForUrl( config.getRootPart(), Constants.WSDL11_NS, urlToFileMap, null );
139 
140 		List<DefintionPartConfig> partList = config.getPartList();
141 		for( DefintionPartConfig part : partList )
142 		{
143 			setFilenameForUrl( part.getUrl(), part.getType(), urlToFileMap, null );
144 		}
145 
146 		for( DefintionPartConfig part : partList )
147 		{
148 			XmlObject obj = null;
149 			if( config.getType() == DefinitionCacheTypeConfig.TEXT )
150 			{
151 				obj = XmlObject.Factory.parse( XmlUtils.getNodeValue( part.getContent().getDomNode() ));
152 			}
153 			else
154 			{
155 				obj = XmlObject.Factory.parse( part.getContent().toString() );
156 			}
157 
158 			replaceImportsAndIncludes( obj, urlToFileMap, part.getUrl() );
159 			obj.save( new File( outFolder, urlToFileMap.get( part.getUrl() ) ) );
160 		}
161 
162 		return folderName + File.separatorChar + urlToFileMap.get( config.getRootPart() );
163 	}
164 	
165 	public StringToStringMap createFilesForExport( String urlPrefix ) throws Exception
166 	{
167 		StringToStringMap result = new StringToStringMap();
168 		Map<String, String> urlToFileMap = new HashMap<String, String>();
169 
170 		if( urlPrefix == null )
171 			urlPrefix = "";
172 		
173 		setFilenameForUrl( config.getRootPart(), Constants.WSDL11_NS, urlToFileMap, urlPrefix );
174 
175 		List<DefintionPartConfig> partList = config.getPartList();
176 		for( DefintionPartConfig part : partList )
177 		{
178 			setFilenameForUrl( part.getUrl(), part.getType(), urlToFileMap, urlPrefix );
179 		}
180 
181 		for( DefintionPartConfig part : partList )
182 		{
183 			XmlObject obj = CachedWsdlLoader.getPartContent( config, part );
184 			replaceImportsAndIncludes( obj, urlToFileMap, part.getUrl() );
185 			String urlString = urlToFileMap.get( part.getUrl() );
186 			if( urlString.startsWith( urlPrefix ))
187 				urlString = urlString.substring( urlPrefix.length() );
188 			
189 			result.put( urlString, obj.xmlText() );
190 		}
191 
192 		return result;
193 	}
194 
195 	private void setFilenameForUrl( String fileUrl, String type, Map<String, String> urlToFileMap, String urlPrefix )
196 				throws MalformedURLException
197 	{
198 		URL url = new URL( fileUrl );
199 		String path = url.getPath();
200 
201 		int ix = path.lastIndexOf( '/' );
202 		String fileName = ix == -1 ? path : path.substring( ix + 1 );
203 
204 		ix = fileName.lastIndexOf( '.' );
205 		if( ix != -1 )
206 			fileName = fileName.substring( 0, ix );
207 
208 		if( type.equals( Constants.WSDL11_NS ) )
209 			fileName += ".wsdl";
210 		else if( type.equals( Constants.XSD_NS ) )
211 			fileName += ".xsd";
212 		else
213 			fileName += ".xml";
214 
215 		while( urlToFileMap.containsValue( fileName ) )
216 		{
217 			ix = fileName.lastIndexOf( '.' );
218 			fileName = fileName.substring( 0, ix ) + "_" + fileName.substring( ix );
219 		}
220 
221 		if( urlPrefix != null )
222 			fileName = urlPrefix + fileName;
223 		
224 		urlToFileMap.put( fileUrl, fileName );
225 	}
226 
227 	private void replaceImportsAndIncludes( XmlObject xmlObject, Map<String, String> urlToFileMap, String baseUrl )
228 				throws Exception
229 	{
230 		XmlObject[] wsdlImports = xmlObject
231 					.selectPath( "declare namespace s='http://schemas.xmlsoap.org/wsdl/' .//s:import/@location" );
232 
233 		for( int i = 0; i < wsdlImports.length; i++ )
234 		{
235 			SimpleValue wsdlImport = ( ( SimpleValue ) wsdlImports[i] );
236 			replaceLocation( urlToFileMap, baseUrl, wsdlImport );
237 		}
238 
239 		XmlObject[] schemaImports = xmlObject
240 					.selectPath( "declare namespace s='http://www.w3.org/2001/XMLSchema' .//s:import/@schemaLocation" );
241 
242 		for( int i = 0; i < schemaImports.length; i++ )
243 		{
244 			SimpleValue schemaImport = ( ( SimpleValue ) schemaImports[i] );
245 			replaceLocation( urlToFileMap, baseUrl, schemaImport );
246 		}
247 
248 		XmlObject[] schemaIncludes = xmlObject
249 					.selectPath( "declare namespace s='http://www.w3.org/2001/XMLSchema' .//s:include/@schemaLocation" );
250 		for( int i = 0; i < schemaIncludes.length; i++ )
251 		{
252 			SimpleValue schemaInclude = ( ( SimpleValue ) schemaIncludes[i] );
253 			replaceLocation( urlToFileMap, baseUrl, schemaInclude );
254 		}
255 	}
256 
257 	private void replaceLocation( Map<String, String> urlToFileMap, String baseUrl, SimpleValue wsdlImport )
258 				throws Exception
259 	{
260 		String location = wsdlImport.getStringValue();
261 		if( location != null )
262 		{
263 			if( location.startsWith( "file:" ) || location.indexOf( "://" ) > 0 )
264 			{
265 				String newLocation = urlToFileMap.get( location );
266 				if( newLocation != null )
267 					wsdlImport.setStringValue( newLocation );
268 				else
269 					throw new Exception( "Missing local file for [" + newLocation + "]" );
270 			}
271 			else
272 			{
273 				String loc = Tools.joinRelativeUrl( baseUrl, location );
274 				String newLocation = urlToFileMap.get( loc );
275 				if( newLocation != null )
276 					wsdlImport.setStringValue( newLocation );
277 				else
278 					throw new Exception( "Missing local file for [" + loc + "]" );
279 			}
280 		}
281 	}
282 
283 	public void close()
284 	{
285 	}
286 }