View Javadoc

1   /*
2    *  soapUI, copyright (C) 2006 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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;
14  
15  import java.io.ByteArrayOutputStream;
16  import java.io.File;
17  import java.io.FileOutputStream;
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.HashSet;
21  import java.util.List;
22  import java.util.Set;
23  
24  import javax.swing.ImageIcon;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.xmlbeans.XmlException;
29  
30  import com.eviware.soapui.SoapUI;
31  import com.eviware.soapui.config.InterfaceConfig;
32  import com.eviware.soapui.config.MockServiceConfig;
33  import com.eviware.soapui.config.ProjectConfig;
34  import com.eviware.soapui.config.SoapuiProjectDocumentConfig;
35  import com.eviware.soapui.config.TestSuiteConfig;
36  import com.eviware.soapui.impl.WorkspaceImpl;
37  import com.eviware.soapui.impl.wsdl.actions.iface.tools.jbossws.WSToolsJava2WsdlAction;
38  import com.eviware.soapui.impl.wsdl.actions.project.AddInterfaceActionFromFile;
39  import com.eviware.soapui.impl.wsdl.actions.project.AddInterfaceActionFromURL;
40  import com.eviware.soapui.impl.wsdl.actions.project.AddNewMockServiceAction;
41  import com.eviware.soapui.impl.wsdl.actions.project.AddNewTestSuiteAction;
42  import com.eviware.soapui.impl.wsdl.actions.project.ReloadProjectAction;
43  import com.eviware.soapui.impl.wsdl.actions.project.RemoveProjectAction;
44  import com.eviware.soapui.impl.wsdl.actions.project.RenameProjectAction;
45  import com.eviware.soapui.impl.wsdl.actions.project.SaveProjectAction;
46  import com.eviware.soapui.impl.wsdl.actions.project.SaveProjectAsAction;
47  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
48  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
49  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
50  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlImporter;
51  import com.eviware.soapui.model.iface.Interface;
52  import com.eviware.soapui.model.mock.MockService;
53  import com.eviware.soapui.model.project.Project;
54  import com.eviware.soapui.model.project.ProjectListener;
55  import com.eviware.soapui.model.settings.Settings;
56  import com.eviware.soapui.model.testsuite.TestSuite;
57  import com.eviware.soapui.settings.ProjectSettings;
58  import com.eviware.soapui.settings.UISettings;
59  import com.eviware.soapui.settings.WsdlSettings;
60  import com.eviware.soapui.support.SoapUIException;
61  import com.eviware.soapui.support.Tools;
62  import com.eviware.soapui.support.UISupport;
63  import com.eviware.soapui.support.action.ActionSupport;
64  
65  /***
66   * WSDL project implementation
67   * 
68   * @author Ole.Matzura
69   */
70  
71  public class WsdlProject extends AbstractWsdlModelItem<ProjectConfig> implements Project
72  {
73     private WorkspaceImpl workspace;
74     private String path;
75     private List<WsdlInterface> interfaces = new ArrayList<WsdlInterface>();
76     private List<WsdlTestSuite> testSuites = new ArrayList<WsdlTestSuite>();
77     private List<WsdlMockService> mockServices = new ArrayList<WsdlMockService>();
78     private Set<ProjectListener> listeners = new HashSet<ProjectListener>();
79     private SoapuiProjectDocumentConfig projectDocument;
80  	private ImageIcon disabledIcon;
81  	private long lastModified;
82     
83     private final static Log log = LogFactory.getLog( WsdlProject.class );
84  
85     public WsdlProject() throws XmlException, IOException
86     {
87     	this( (WorkspaceImpl)null );
88     }
89  
90     public WsdlProject( String path ) throws XmlException, IOException, SoapUIException
91     {
92     	this( path, null );
93     }
94     
95     public WsdlProject( WorkspaceImpl workspace ) throws XmlException, IOException 
96     {
97     	super( null, workspace, "/project.gif" );
98        this.workspace = workspace;
99     	projectDocument = SoapuiProjectDocumentConfig.Factory.newInstance();
100    	
101    	setConfig( projectDocument.addNewSoapuiProject() );
102       
103       initActions();
104    }
105 
106    public WsdlProject(String path, WorkspaceImpl workspace ) throws SoapUIException
107    {
108    	this( path, workspace, true );
109    }
110    
111    public WsdlProject(String path, WorkspaceImpl workspace, boolean create ) throws SoapUIException
112    {
113    	super( null, workspace, "/project.gif" );
114    	
115       this.workspace = workspace;
116    	this.path = path;
117       File file = new File(path);
118       
119       if( file.exists())
120       {
121          loadProject( file );
122       }
123       else if( create )
124       {
125          projectDocument = SoapuiProjectDocumentConfig.Factory.newInstance();
126          setConfig( projectDocument.addNewSoapuiProject() );
127       }
128       else
129       {
130       	disabledIcon = UISupport.createImageIcon( "/disabledProject.gif" );
131       }
132       
133       setProjectRoot(path);
134      	initActions();
135    }
136 
137 	private void loadProject( File file ) throws SoapUIException
138 	{
139 		try
140 		{
141 			lastModified = file.lastModified();
142 			projectDocument = SoapuiProjectDocumentConfig.Factory.parse( file );
143 		}
144 		catch (Exception e)
145 		{
146 			throw new SoapUIException( "Failed to create project from file [" + file.getName() + "]", e );
147 		}
148 		
149 		setConfig( projectDocument.getSoapuiProject() );
150 		
151 		// removed cached definitions if caching is disabled
152 		if( !getSettings().getBoolean( WsdlSettings.CACHE_WSDLS ))
153 		{
154 			removeDefinitionCaches( projectDocument );
155 		}
156 		
157 		log.info( "Loaded project from [" + file.getAbsolutePath() + "]" );
158 		 
159 		List<InterfaceConfig> interfaceConfigs = getConfig().getInterfaceList();
160 		for (InterfaceConfig config : interfaceConfigs)
161 		{
162 		   interfaces.add( new WsdlInterface( this, config ));
163 		}
164 
165 		List<TestSuiteConfig> testSuiteConfigs = getConfig().getTestSuiteList();
166 		for( TestSuiteConfig config : testSuiteConfigs )
167 		{
168 		   testSuites.add( new WsdlTestSuite( this, config ));
169 		}
170 		
171 		List<MockServiceConfig> mockServiceConfigs = getConfig().getMockServiceList();
172 		for( MockServiceConfig config : mockServiceConfigs )
173 		{
174 		   mockServices.add( new WsdlMockService( this, config ));
175 		}
176 	}
177 
178 	private void setProjectRoot(String path)
179 	{
180 		if( path != null && projectDocument != null )
181       {
182       	int ix = path.lastIndexOf( File.separatorChar );
183       	if( ix > 0 )
184       		getSettings().setString( ProjectSettings.PROJECT_ROOT, path.substring( 0, ix ) );
185       }
186 	}
187 	
188 	@Override
189 	public ImageIcon getIcon()
190 	{
191 		if( projectDocument != null )
192 			return super.getIcon();
193 		else
194 			return disabledIcon;
195 	}
196 	
197 	@Override
198 	public String getName()
199 	{
200 		if( projectDocument != null )
201 			return super.getName();
202 		else
203 		{
204 			int ix = path.lastIndexOf( File.separatorChar );
205 			String name = ix == -1 ? path : path.substring( ix+1 );
206 			return name + " (disabled)";
207 		}
208 	}
209 	
210 	@Override
211 	public String getDescription()
212 	{
213 		return projectDocument == null ? getName() : super.getDescription();
214 	}
215 
216 	private void initActions()
217 	{
218 		if( projectDocument == null )
219 		{
220 			addAction( new ReloadProjectAction( this ));
221 			addAction( new RemoveProjectAction( this ));
222 			addAction( ActionSupport.SEPARATOR_ACTION );
223 	      addAction( new ShowOnlineHelpAction( HelpUrls.PROJECT_HELP_URL ));
224 		}
225 		else
226 		{
227 	      addAction( new AddInterfaceActionFromURL( this ) );
228 	      addAction( new AddInterfaceActionFromFile( this ) );
229 	      addAction( ActionSupport.SEPARATOR_ACTION );
230 	      addAction( new WSToolsJava2WsdlAction( this ) );
231 	      addAction( ActionSupport.SEPARATOR_ACTION );
232 	      addAction( new AddNewTestSuiteAction( this ) );
233 	      addAction( new AddNewMockServiceAction( this ) );
234 	      addAction( ActionSupport.SEPARATOR_ACTION );
235 	      addAction( new RenameProjectAction( this ) );
236 	      addAction( new RemoveProjectAction( this ) );
237 	      addAction( new ReloadProjectAction( this ));
238 	      addAction( ActionSupport.SEPARATOR_ACTION );
239 	      addAction( new SaveProjectAction( this ));
240 	      addAction( new SaveProjectAsAction( this ));
241 	      addAction( ActionSupport.SEPARATOR_ACTION );
242 	      addAction( new ShowOnlineHelpAction( HelpUrls.PROJECT_HELP_URL ));
243 		}
244 	}
245 	
246    public WorkspaceImpl getWorkspace()
247    {
248       return workspace;
249    }
250 
251 	public WsdlInterface getInterfaceAt(int index)
252    {
253       return interfaces.get( index );
254    }
255 
256    public WsdlInterface getInterfaceByName(String interfaceName)
257 	{
258 		return (WsdlInterface) getWsdlModelItemByName( interfaces, interfaceName );
259 	}
260 
261 	public int getInterfaceCount()
262    {
263       return interfaces.size();
264    }
265 
266    public String getPath()
267 	{
268 		return path;
269 	}
270 
271 	public boolean save() throws IOException 
272    {
273 		if( projectDocument == null )
274 			return true;
275 		
276       if( path == null )
277       {
278          File file = UISupport.getFileDialogs().saveAs(this, "Save project " + getName());
279          if( file == null ) return false;
280 
281          path = file.getAbsolutePath();
282       }
283       
284       File projectFile = new File( path );
285       
286       while( projectFile.exists() && !projectFile.canWrite() )
287       {
288       	if( UISupport.confirm( "Project file [" + path + "] can not be written to, save to new file?", "Save Project" ))
289       	{
290       		projectFile = UISupport.getFileDialogs().saveAs(this, "Save project " + getName());
291             if( projectFile == null ) return false;
292 
293             path = projectFile.getAbsolutePath();
294       	}
295       	else return false;
296       }
297       
298       
299       // check modified 
300 		if( projectFile.exists() && lastModified != 0 && lastModified < projectFile.lastModified() )
301 		{
302 			if( !UISupport.confirm( 
303 						"Project file for [" + getName() + "] has been modified externally, overwrite?", 
304 						"Save Project" ))
305 				return false;
306 		}
307       
308    	long size = 0;
309    	
310    	if( projectFile.exists() && getSettings().getBoolean( UISettings.CREATE_BACKUP ))
311    	{
312    		createBackup( projectFile );
313    	}
314    	
315    	// check for caching
316    	if( !getSettings().getBoolean( WsdlSettings.CACHE_WSDLS ))
317    	{
318    		// no caching -> create copy and remove definition cachings
319    		SoapuiProjectDocumentConfig config = (SoapuiProjectDocumentConfig) projectDocument.copy();
320    		removeDefinitionCaches(config);
321    		
322    		config.getSoapuiProject().setSoapuiVersion( SoapUI.SOAPUI_VERSION );
323    		config.save( projectFile );
324    	}
325    	else
326    	{
327       	try
328 			{
329       		// save to temporary buffer to avoid corruption of file
330 				projectDocument.getSoapuiProject().setSoapuiVersion( SoapUI.SOAPUI_VERSION );
331 				ByteArrayOutputStream writer = new ByteArrayOutputStream( 8192 );
332 				projectDocument.save( writer );
333 				FileOutputStream out = new FileOutputStream( projectFile );
334 				writer.writeTo( out );
335 				out.close();
336 				lastModified = projectFile.lastModified();
337 				size = writer.size();
338 			}
339 			catch (Throwable t)
340 			{
341 				t.printStackTrace();
342 				UISupport.showErrorMessage( "Failed to save project [" + getName() + "]: " + t.toString() );
343 				return false;
344 			}
345    	}
346    	
347 		log.info( "Saved project [" + getName() + "] to [" + projectFile.getAbsolutePath() + " - " +
348 				size + " bytes" );
349 		setProjectRoot(path);
350 		return true;
351 }
352 
353 	private void createBackup(File projectFile) throws IOException
354 	{
355 		String backupFolderName = getSettings().getString( UISettings.BACKUP_FOLDER, "" );
356 		
357 		File backupFolder = new File( backupFolderName );
358 		if( !backupFolder.isAbsolute() )
359 		{
360 			backupFolder = new File( projectFile.getParentFile(), backupFolderName );
361 		}
362 		
363 		if( !backupFolder.exists() )
364 			backupFolder.mkdirs();
365 		
366 		File backupFile = new File( backupFolder, projectFile.getName() + ".backup" );
367 		log.info( "Backing up [" + projectFile + "] to [" + backupFile + "]" );
368 		
369 		Tools.copyFile( projectFile, backupFile, true );
370 	}
371 
372 	private void removeDefinitionCaches(SoapuiProjectDocumentConfig config)
373 	{
374 		for( InterfaceConfig ifaceConfig : config.getSoapuiProject().getInterfaceList() )
375 		{
376 			if( ifaceConfig.isSetDefinitionCache() )
377 			{
378 				log.info( "Removing definition cache from interface [" + ifaceConfig.getName() + "]" );
379 				ifaceConfig.unsetDefinitionCache();
380 			}
381 		}
382 	}
383    
384    public WsdlInterface [] importWsdl( String url, boolean createRequests ) throws SoapUIException
385    {
386    	if( projectDocument == null )
387    		return null;
388    	
389    	WsdlInterface[] result;
390    	
391       try
392       {
393          result = WsdlImporter.getInstance().importWsdl( this, url );
394       }
395       catch (Exception e)
396       {
397          log.error( "Error importing wsdl: " + e );
398          e.printStackTrace();
399          throw new SoapUIException( "Error importing wsdl", e );
400       }
401       
402       try
403       {      
404 			if( createRequests && result != null )
405          {
406          	for (WsdlInterface iface : result)
407 				{
408          		for( int c = 0; c < iface.getOperationCount(); c++ )
409          		{
410          			WsdlOperation operation = (WsdlOperation) iface.getOperationAt( c );
411          			WsdlRequest request = operation.addNewRequest( "Request 1");
412                   try
413                   {
414                      request.setRequestContent( operation.createRequest( true ));
415                   }
416                   catch (Exception e)
417                   {
418                      e.printStackTrace();
419                   }
420          		}
421 				}
422          }
423       }
424       catch (Exception e)
425       {
426       	log.error( "Error creating requests: " + e.getMessage() );
427          throw new SoapUIException( "Error creating requests", e );
428       }
429       
430       return result;
431    }
432    
433    public WsdlInterface addNewInterface( String name )
434    {
435       WsdlInterface iface = new WsdlInterface( this, getConfig().addNewInterface());
436       iface.setName( name );
437       interfaces.add( iface );
438       fireInterfaceAdded( iface );
439 
440       return iface;
441    }
442    
443    public void addProjectListener(ProjectListener listener)
444    {
445       listeners.add( listener );
446    }
447    
448    public void removeProjectListener(ProjectListener listener)
449    {
450       listeners.remove( listener );
451    }
452    
453    public void fireInterfaceAdded( WsdlInterface iface )
454    {
455       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
456       
457       for (int c = 0; c < a.length; c++ )
458       {
459          a[c].interfaceAdded( iface );
460       }
461    }
462    
463    public void fireInterfaceRemoved( WsdlInterface iface )
464    {
465       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
466       
467       for (int c = 0; c < a.length; c++ )
468       {
469          a[c].interfaceRemoved( iface );
470       }
471    }
472    
473    
474    public void fireTestSuiteAdded( WsdlTestSuite testSuite )
475    {
476       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
477       
478       for (int c = 0; c < a.length; c++ )
479       {
480          a[c].testSuiteAdded( testSuite );
481       }
482    }
483    
484    public void fireTestSuiteRemoved( WsdlTestSuite testSuite )
485    {
486       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
487       
488       for (int c = 0; c < a.length; c++ )
489       {
490          a[c].testSuiteRemoved( testSuite );
491       }
492    } 
493    
494    public void fireMockServiceAdded( WsdlMockService mockService )
495    {
496       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
497       
498       for (int c = 0; c < a.length; c++ )
499       {
500          a[c].mockServiceAdded( mockService );
501       }
502    }
503    
504    public void fireMockServiceRemoved( WsdlMockService mockService )
505    {
506       ProjectListener[] a = listeners.toArray( new ProjectListener[listeners.size()] );
507       
508       for (int c = 0; c < a.length; c++ )
509       {
510          a[c].mockServiceRemoved( mockService );
511       }
512    }
513    
514    public void removeInterface(WsdlInterface iface )
515    {
516       int ix = interfaces.indexOf( iface );
517       interfaces.remove( ix );
518       try
519       {
520       	fireInterfaceRemoved( iface );
521       }
522       finally
523       {
524       	iface.release();
525       	getConfig().removeInterface( ix );
526       }
527    }
528    
529    public void removeTestSuite(WsdlTestSuite testSuite )
530    {
531       int ix = testSuites.indexOf( testSuite );
532       testSuites.remove( ix );
533       
534       try
535       {
536       	fireTestSuiteRemoved( testSuite );
537       }
538       finally
539       {
540       	testSuite.release();
541       	getConfig().removeTestSuite( ix );
542       }
543    }
544 
545    public boolean isDisabled()
546    {
547    	return projectDocument == null;
548    }
549    
550    public int getTestSuiteCount()
551    {
552       return testSuites.size();
553    }
554 
555    public TestSuite getTestSuiteAt(int index)
556    {
557       return testSuites.get( index );
558    }
559 
560    public WsdlTestSuite getTestSuiteByName(String testSuiteName)
561 	{
562 		return  ( WsdlTestSuite ) getWsdlModelItemByName( testSuites, testSuiteName );
563 	}
564 
565    public WsdlTestSuite addNewTestSuite(String name)
566    {
567       WsdlTestSuite testSuite = new WsdlTestSuite( this, getConfig().addNewTestSuite());
568       testSuite.setName( name );
569       testSuites.add( testSuite );
570       fireTestSuiteAdded( testSuite );
571 
572       return testSuite;
573    }
574 
575 	public WsdlTestSuite cloneTestSuite(WsdlTestSuite testSuite, String name)
576 	{
577 		TestSuiteConfig testSuiteConfig = getConfig().addNewTestSuite();
578 		testSuiteConfig.set( testSuite.getConfig() );
579 		WsdlTestSuite newTestSuite = new WsdlTestSuite( this, testSuiteConfig );
580 		newTestSuite.setName( name );
581       testSuites.add( newTestSuite );
582       fireTestSuiteAdded( newTestSuite );
583 
584       return newTestSuite;
585 	}
586 	
587 	public boolean isCacheDefinitions()
588 	{
589 		return getSettings().getBoolean( WsdlSettings.CACHE_WSDLS );
590 	}
591 	
592 	public void setCacheDefinitions( boolean cacheDefinitions )
593 	{
594 		getSettings().setBoolean( WsdlSettings.CACHE_WSDLS, cacheDefinitions );
595 	}
596 
597 	public boolean saveTo(String fileName) throws IOException
598 	{
599 		String oldPath = path;
600 		path = fileName;
601 		boolean result = save();
602 		if( !result )
603 			path = oldPath;
604 		
605 		setProjectRoot(path);
606 		
607 		return result;
608 	}
609 
610 	public void release()
611 	{
612 		super.release();
613 		
614 		for( WsdlTestSuite testSuite : testSuites )
615 			testSuite.release();
616 
617 		for( WsdlInterface iface : interfaces )
618 			iface.release();
619 	}
620 
621 	public WsdlMockService cloneMockService( WsdlMockService mockService, String name )
622 	{
623 		MockServiceConfig testSuiteConfig = getConfig().addNewMockService();
624 		testSuiteConfig.set( mockService.getConfig() );
625 		WsdlMockService newMockService = new WsdlMockService( this, testSuiteConfig );
626 		newMockService.setName( name );
627       mockServices.add( newMockService );
628       fireMockServiceAdded( newMockService );
629 
630       return newMockService;
631 	}
632 	
633 	public WsdlMockService addNewMockService( String name )
634 	{
635 		WsdlMockService mockService = new WsdlMockService( this, getConfig().addNewMockService());
636       mockService.setName( name );
637       mockServices.add( mockService );
638       fireMockServiceAdded( mockService );
639 
640       return mockService;
641 	}
642 
643 	public MockService getMockServiceAt( int index )
644 	{
645 		return mockServices.get( index );
646 	}
647 
648 	public MockService getMockServiceByName( String mockServiceName )
649 	{
650 		return (MockService) getWsdlModelItemByName( mockServices, mockServiceName );
651 	}
652 
653 	public int getMockServiceCount()
654 	{
655 		return mockServices.size();
656 	}
657 
658 	public void removeMockService(WsdlMockService mockService )
659    {
660       int ix = mockServices.indexOf( mockService );
661       mockServices.remove( ix );
662       
663       try
664       {
665       	fireMockServiceRemoved( mockService );
666       }
667       finally
668       {
669       	mockService.release();
670       	getConfig().removeMockService( ix );
671       }
672    }
673 
674 	public List<TestSuite> getTestSuites()
675 	{
676 		return new ArrayList<TestSuite>( testSuites );
677 	}
678 
679 	public List<MockService> getMockServices()
680 	{
681 		return new ArrayList<MockService>( mockServices );
682 	}
683 
684 	public List<Interface> getInterfaces()
685 	{
686 		return new ArrayList<Interface>( interfaces );
687 	}
688 
689 	public void reload( File file ) throws SoapUIException
690 	{
691 		this.path = file.getAbsolutePath();
692 		getWorkspace().reloadProject( this );
693 	}
694 
695    public boolean hasNature(String natureId)
696    {
697       Settings projectSettings = getSettings();
698       String projectNature = projectSettings.getString( ProjectSettings.PROJECT_NATURE, null );
699       return natureId.equals(projectNature);
700    }
701 }