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;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.config.SoapuiWorkspaceDocumentConfig;
17  import com.eviware.soapui.config.WorkspaceProjectConfig;
18  import com.eviware.soapui.config.WorkspaceProjectConfig.Status;
19  import com.eviware.soapui.config.WorkspaceProjectConfig.Type;
20  import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
21  import com.eviware.soapui.impl.wsdl.WsdlProject;
22  import com.eviware.soapui.impl.wsdl.WsdlProjectFactory;
23  import com.eviware.soapui.impl.wsdl.support.PathUtils;
24  import com.eviware.soapui.model.ModelItem;
25  import com.eviware.soapui.model.project.Project;
26  import com.eviware.soapui.model.project.ProjectFactoryRegistry;
27  import com.eviware.soapui.model.settings.Settings;
28  import com.eviware.soapui.model.support.AbstractModelItem;
29  import com.eviware.soapui.model.workspace.Workspace;
30  import com.eviware.soapui.model.workspace.WorkspaceListener;
31  import com.eviware.soapui.settings.UISettings;
32  import com.eviware.soapui.support.MessageSupport;
33  import com.eviware.soapui.support.SoapUIException;
34  import com.eviware.soapui.support.UISupport;
35  import com.eviware.soapui.support.resolver.ResolveDialog;
36  import org.apache.log4j.Logger;
37  import org.apache.xmlbeans.XmlException;
38  import org.apache.xmlbeans.XmlOptions;
39  
40  import javax.swing.*;
41  import java.io.File;
42  import java.io.IOException;
43  import java.util.*;
44  
45  /***
46   * Default Workspace implementation
47   * 
48   * @author Ole.Matzura
49   */
50  
51  public class WorkspaceImpl extends AbstractModelItem implements Workspace
52  {
53  	private final static Logger log = Logger.getLogger( WorkspaceImpl.class );
54  	public static final MessageSupport messages = MessageSupport.getMessages( WorkspaceImpl.class );
55  	
56  	private List<Project> projectList = new ArrayList<Project>();
57  	private SoapuiWorkspaceDocumentConfig workspaceConfig;
58  	private String path = null;
59  	private Set<WorkspaceListener> listeners = new HashSet<WorkspaceListener>();
60  	private ImageIcon workspaceIcon;
61  	private XmlBeansSettingsImpl settings;
62  	private TreeMap<String, String> projectOptions;
63     private ResolveDialog resolver;
64  
65     public WorkspaceImpl( String path, TreeMap<String, String> projectOptions ) throws XmlException, IOException
66  	{
67  		if ( projectOptions == null ) {
68  			this.projectOptions = new TreeMap<String, String>();
69  		} else {
70  			this.projectOptions = projectOptions;
71  		}
72  		File file = new File( path );
73  		this.path = file.getAbsolutePath();
74  		loadWorkspace( file );
75  		workspaceIcon = UISupport.createImageIcon( "/workspace.gif" );
76  	}
77  
78  	public void switchWorkspace( File file ) throws SoapUIException
79  	{
80  		// check first if valid workspace file
81  		if( file.exists() )
82  		{
83  			try
84  			{
85  				SoapuiWorkspaceDocumentConfig.Factory.parse( file );
86  			}
87  			catch( Exception e )
88  			{
89  				throw new SoapUIException( messages.get("FailedToLoadWorkspaceException") + e.toString() ); 
90  			}
91  		}
92  		
93  		fireWorkspaceSwitching();
94  		
95  		while( projectList.size() > 0 )
96  		{
97  			Project project = projectList.remove( 0 );
98  			try
99  			{
100 				fireProjectRemoved( project );
101 			}
102 			finally
103 			{
104 				project.release();
105 			}
106 		}
107 		
108 		try
109 		{
110 			String oldName = getName();
111 		
112 			loadWorkspace( file );
113 			this.path = file.getAbsolutePath();
114 			
115 			for( Project project : projectList )
116 			{
117 				fireProjectAdded( project );
118 			}
119 			
120 			notifyPropertyChanged( ModelItem.NAME_PROPERTY, oldName, getName() );
121 		}
122 		catch(Exception e )
123 		{
124 			SoapUI.logError( e );
125 		}
126 		
127 		fireWorkspaceSwitched();
128 	}
129 	
130 	public void loadWorkspace( File file ) throws XmlException, IOException
131 	{
132 		if( file.exists() )
133 		{
134 			log.info( messages.get("FailedToLoadWorkspaceFrom", file.getAbsolutePath() ) );
135 			workspaceConfig = SoapuiWorkspaceDocumentConfig.Factory.parse( file );
136 			if( workspaceConfig.getSoapuiWorkspace().getSettings() == null )
137 				workspaceConfig.getSoapuiWorkspace().addNewSettings();
138 
139 			settings = new XmlBeansSettingsImpl( this, SoapUI.getSettings(), workspaceConfig
140 						.getSoapuiWorkspace().getSettings() );
141 
142 			boolean closeOnStartup = getSettings().getBoolean( UISettings.CLOSE_PROJECTS );
143 			List<WorkspaceProjectConfig> projects = workspaceConfig.getSoapuiWorkspace().getProjectList();
144 			for( int i = 0; i < projects.size(); i++ )
145 			{
146 				WorkspaceProjectConfig wsc = projects.get( i );
147 				String str = PathUtils.denormalizePath(wsc.getStringValue());
148 
149 				str = PathUtils.adjustRelativePath( str, getProjectRoot(), this );
150 				
151 				try
152 				{
153 //					WsdlProject project = new WsdlProject( str, this, false, !closeOnStartup &&
154 //								wsc.getStatus() != Status.CLOSED && wsc.getType() != Type.REMOTE, wsc.getName(), null);
155 					WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory("wsdl").createNew( str, this, false, !closeOnStartup &&
156 							wsc.getStatus() != Status.CLOSED && wsc.getType() != Type.REMOTE, wsc.getName(), null);
157 					
158 					projectList.add( project );
159 				}
160 				catch( Exception e )
161 				{
162 					UISupport.showErrorMessage( messages.get("FailedToLoadProjectInWorkspace", str) 
163 								+ e.getMessage() );  
164 
165 					SoapUI.logError( e );
166 				}
167 			}
168 		}
169 		else
170 		{
171 			workspaceConfig = SoapuiWorkspaceDocumentConfig.Factory.newInstance();
172 			workspaceConfig.addNewSoapuiWorkspace().setName( messages.get("DefaultWorkspaceName") ); 
173 			workspaceConfig.getSoapuiWorkspace().addNewSettings();
174 
175 			settings = new XmlBeansSettingsImpl( this, SoapUI.getSettings(), workspaceConfig
176 						.getSoapuiWorkspace().getSettings() );
177 		}
178 	}
179 
180 	public void setPath( String path )
181 	{
182 		this.path = path;
183 	}
184 
185 	public Project[] getProjects()
186 	{
187 		return projectList.toArray( new Project[projectList.size()] );
188 	}
189 
190 	public void setName( String name )
191 	{
192 		String oldName = getName();
193 		
194 		workspaceConfig.getSoapuiWorkspace().setName( name );
195 		notifyPropertyChanged( ModelItem.NAME_PROPERTY, oldName, name );
196 	}
197 	
198 	public void setDescription( String description )
199 	{
200 		String oldDescription = getDescription();
201 		
202 		workspaceConfig.getSoapuiWorkspace().setDescription( description );
203 		notifyPropertyChanged( ModelItem.DESCRIPTION_PROPERTY, oldDescription, description );
204 	}
205 
206 	public String getName()
207 	{
208 		return workspaceConfig.getSoapuiWorkspace().isSetName() ? workspaceConfig.getSoapuiWorkspace().getName() : messages.get("DefaultWorkspaceName"); 
209 	}
210 
211 	public Project getProjectAt( int index )
212 	{
213 		return projectList.get( index );
214 	}
215 
216 	public Project getProjectByName( String projectName )
217 	{
218 		for( Project project : projectList )
219 		{
220 			if( project.getName().equals( projectName ) )
221 				return project;
222 		}
223 
224 		return null;
225 	}
226 
227 	public int getProjectCount()
228 	{
229 		return projectList.size();
230 	}
231 
232 	public void onClose()
233 	{
234 		save( !getSettings().getBoolean(UISettings.AUTO_SAVE_PROJECTS_ON_EXIT ));
235 	}
236 
237 	public void save( boolean workspaceOnly )
238 	{
239 		save( workspaceOnly, false );
240 	}
241 	
242 	public void save( boolean workspaceOnly, boolean skipProjectsWithRunningTests )
243 	{
244 		try
245 		{
246 			// not saved?
247 			if( path == null )
248 			{
249 				File file = UISupport.getFileDialogs().saveAs( this, messages.get("SaveWorkspace.Title"), ".xml", 
250 							"XML Files (*.xml)", null ); 
251 				if( file == null )
252 					return;
253 
254 				path = file.getAbsolutePath();
255 			}
256 			
257 			List<WorkspaceProjectConfig> projects = new ArrayList<WorkspaceProjectConfig>();
258 			
259 			// save projects first
260 			for( int c = 0; c < getProjectCount(); c++ )
261 			{
262 				WsdlProject project = ( WsdlProject ) getProjectAt( c );
263 
264 				if( !workspaceOnly  )
265 				{
266 					if( skipProjectsWithRunningTests && SoapUI.getTestMonitor().hasRunningTests( project ))
267 					{
268 						log.warn( messages.get("ProjectHasRunningTests.Warning", project.getName()) ); 
269 					}
270 					else
271 					{
272 						String path = project.getPath();
273 						if( path == null )
274 						{
275 							if( UISupport.confirm( messages.get("ProjectHasNotBeenSaved.Label", project.getName()), 
276 									messages.get("ProjectHasNotBeenSaved.Title") )) 
277 							{
278 								project.save();
279 							}
280 						}
281 						else
282 						{
283 							project.save();
284 						}
285 					}
286 				}
287 
288 				String path = project.getPath();
289 				if( path != null )
290 				{
291 					path = PathUtils.createRelativePath( path, getProjectRoot(), this );
292 					
293 					WorkspaceProjectConfig wpc = WorkspaceProjectConfig.Factory.newInstance();
294 					wpc.setStringValue( PathUtils.normalizePath( path ));
295 					if( project.isRemote() )
296 						wpc.setType( Type.REMOTE );
297 					
298 					if( !project.isOpen() ) {
299 						if( project.getEncrypted() == 0 ) {
300 							wpc.setStatus( Status.CLOSED );
301 						} else {
302 							wpc.setStatus( Status.CLOSED_AND_ENCRYPTED );
303 						}
304 					}
305 					
306 					wpc.setName( project.getName() );
307 					projects.add( wpc );
308 				}
309 			}
310 
311 			workspaceConfig.getSoapuiWorkspace().setProjectArray(
312 						projects.toArray( new WorkspaceProjectConfig[projects.size()] ) );
313 			workspaceConfig.getSoapuiWorkspace().setSoapuiVersion( SoapUI.SOAPUI_VERSION );
314 
315 			File workspaceFile = new File( path );
316 			workspaceConfig.save( workspaceFile, new XmlOptions().setSavePrettyPrint() );
317 
318 			log.info( messages.get("SavedWorkspace.Info", workspaceFile.getAbsolutePath() )); //$NON-NLS-1$ //$NON-NLS-2$
319 		}
320 		catch( IOException e )
321 		{
322 			log.error( messages.get("FailedToSaveWorkspace.Error") + e.getMessage(), e ); //$NON-NLS-1$
323 		}
324 	}
325 
326 	public void addWorkspaceListener( WorkspaceListener listener )
327 	{
328 		listeners.add( listener );
329 	}
330 
331 	public void removeWorkspaceListener( WorkspaceListener listener )
332 	{
333 		listeners.remove( listener );
334 	}
335 
336 	public Project importProject( String fileName ) throws SoapUIException
337 	{
338 		File projectFile = new File( fileName );
339 		WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory("wsdl").createNew(projectFile.getAbsolutePath(), this );
340 
341       projectList.add( project );
342 		fireProjectAdded( project );
343 
344       resolveProject( project );
345 
346       save( true );
347 
348 		return project;
349 	}
350 
351    public void resolveProject( WsdlProject project )
352    {
353       if( resolver ==null)
354       {
355          resolver = new ResolveDialog( "Resolve Project", "Resolve imported project", null );
356          resolver.setShowOkMessage( false );
357       }
358 
359       resolver.resolve( project );
360    }
361 
362    public WsdlProject createProject( String name ) throws SoapUIException
363 	{
364 		File projectFile = new File( createProjectFileName( name ) );
365 		File file = UISupport.getFileDialogs().saveAs( this, messages.get("CreateProject.Title"), ".xml", 
366 					"XML Files (*.xml)", projectFile ); 
367 		if( file == null )
368 			return null;
369 
370 		return createProject( name, file );
371 	}
372 
373 	public WsdlProject createProject( String name, File file ) throws SoapUIException
374 	{
375 		File projectFile = file;
376 		while( projectFile != null && projectFile.exists() )
377 		{
378 			Boolean result = Boolean.FALSE;
379 			while( !result.booleanValue() )
380 			{
381 				result = UISupport.confirmOrCancel( messages.get("OverwriteProject.Label"), messages.get("OverwriteProject.Title") ); 
382 				if( result == null )
383 					return null;
384 				if( result.booleanValue() )
385 				{
386 					projectFile.delete();
387 				}
388 				else
389 				{
390 					projectFile = UISupport.getFileDialogs().saveAs( this, messages.get("CreateProject.Title"), ".xml",
391 								"XML Files (*.xml)", projectFile ); //$NON-NLS-1$
392 					if( projectFile == null )
393 						return null;
394 					else
395 						break;
396 				}
397 			}
398 		}
399 
400 //		WsdlProject project = new WsdlProject( projectFile == null ? null : projectFile.getAbsolutePath(), this );
401 		WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory(WsdlProjectFactory.WSDL_TYPE).createNew( projectFile == null ? null : projectFile.getAbsolutePath(), this );
402 		
403 		project.setName( name );
404 		projectList.add( project );
405 
406 		fireProjectAdded( project );
407 
408 		try
409 		{
410 			if( projectFile != null )
411 				project.save();
412 		}
413 		catch( IOException e )
414 		{
415 			log.error( messages.get("FailedToSaveProject.Error") + e.getMessage(), e ); 
416 		}
417 //		save( true );
418 
419 		return project;
420 	}
421 
422 	private void fireProjectAdded( Project project )
423 	{
424 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
425 		{
426 			WorkspaceListener listener = iter.next();
427 			listener.projectAdded( project );
428 		}
429 	}
430 	
431 	private void fireWorkspaceSwitching()
432 	{
433 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
434 		{
435 			WorkspaceListener listener = iter.next();
436 			listener.workspaceSwitching( this );
437 		}
438 	}
439 	
440 	private void fireWorkspaceSwitched()
441 	{
442 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
443 		{
444 			WorkspaceListener listener = iter.next();
445 			listener.workspaceSwitched( this );
446 		}
447 	}
448 
449 	private String createProjectFileName( String name )
450 	{
451 		return name + "-soapui-project.xml"; //$NON-NLS-1$
452 	}
453 
454 	public void removeProject( Project project )
455 	{
456 		int ix = projectList.indexOf( project );
457 		if( ix == -1 )
458 			throw new RuntimeException( "Project [" + project.getName() 
459 						+ "] not available in workspace for removal" ); 
460 
461 		projectList.remove( ix );
462 
463 		try
464 		{
465 			fireProjectRemoved( project );
466 		}
467 		finally
468 		{
469 			project.release();
470 //			workspaceConfig.getSoapuiWorkspace().removeProject( ix );
471 		}
472 	}
473 	
474 	public Project reloadProject( Project project ) throws SoapUIException
475 	{
476 		int ix = projectList.indexOf( project );
477 		if( ix == -1 )
478 			throw new RuntimeException( "Project [" + project.getName() //$NON-NLS-1$
479 						+ "] not available in workspace for reload" ); //$NON-NLS-1$
480 
481 		projectList.remove( ix );
482 		fireProjectRemoved( project );
483 		
484 		String tempName = project.getName();
485 		project.release();
486 //		project = new WsdlProject( project.getPath(), this, false, true, tempName, null );
487 		project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory("wsdl").createNew(project.getPath(), this, false, true, tempName, null);
488 		projectList.add( ix, project );
489 
490 		fireProjectAdded( project );
491 
492 //		workspaceConfig.getSoapuiWorkspace().getProjectArray( ix ).setStringValue( project.getPath() );
493 		
494 		return project;
495 	}
496 
497 	private void fireProjectRemoved( Project project )
498 	{
499 		WorkspaceListener[] listenerArray = listeners
500 					.toArray( new WorkspaceListener[listeners.size()] );
501 		for( int c = 0; c < listenerArray.length; c++ )
502 		{
503 			listenerArray[c].projectRemoved( project );
504 		}
505 	}
506 
507 	public ImageIcon getIcon()
508 	{
509 		return workspaceIcon;
510 	}
511 
512 	public Settings getSettings()
513 	{
514 		return settings;
515 	}
516 
517 	public int getIndexOfProject( Project project )
518 	{
519 		return projectList.indexOf( project );
520 	}
521 
522 	public String getPath()
523 	{
524 		return path;
525 	}
526 	
527 	public String getProjectRoot()
528 	{
529 		return workspaceConfig.getSoapuiWorkspace().getProjectRoot();
530 	}
531 
532 	public void setProjectRoot( String workspaceRoot )
533 	{
534 		workspaceConfig.getSoapuiWorkspace().setProjectRoot( workspaceRoot );
535 	}
536 	
537 	public void release()
538 	{
539 		settings.release();
540 
541 		for( Project project : projectList )
542 			project.release();
543 	}
544 
545 	public List<? extends Project> getProjectList()
546 	{
547 		return projectList;
548 	}
549 
550 	public String getDescription()
551 	{
552 		return workspaceConfig.getSoapuiWorkspace().getDescription();
553 	}
554 
555 	public WsdlProject importRemoteProject( String url ) throws SoapUIException
556 	{
557 //		WsdlProject project = new WsdlProject( url, this, false );
558 		WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory("wsdl").createNew(url, this, false);
559 		projectList.add( project );
560 		fireProjectAdded( project );
561 
562       resolveProject( project );
563 
564       save( true );
565 
566 		return project;
567 	}
568 
569 	public void closeProject( Project project )
570 	{
571 		int oldProjectEncrypt = ((WsdlProject) project).getEncrypted();
572 		int ix = projectList.indexOf( project );
573 		if( ix == -1 )
574 			throw new RuntimeException( "Project [" + project.getName() 
575 						+ "] not available in workspace for close" ); 
576 
577 		projectList.remove( ix );
578 		fireProjectRemoved( project );
579 		
580 		String name = project.getName();
581 		project.release();
582 		
583 		try
584 		{
585 //			project = new WsdlProject( project.getPath(), this, false, false, name, null );
586 			project = ProjectFactoryRegistry.getProjectFactory(WsdlProjectFactory.WSDL_TYPE).createNew(project.getPath(), this, false, false, name, null);
587 			((WsdlProject)project).setEncrypted( oldProjectEncrypt );
588 			projectList.add( ix, project );
589 			fireProjectAdded( project );
590 		}
591 		catch( Exception e )
592 		{
593 			UISupport.showErrorMessage( messages.get("FailedToCloseProject.Error", name ) + e.getMessage() ); 
594 			SoapUI.logError( e );
595 		}
596 	}
597 
598 	public List<Project> getOpenProjectList()
599 	{
600 		List<Project> availableProjects = new ArrayList<Project>(); 
601 		
602 		for( Project project : projectList )
603 			if( project.isOpen() )
604 				availableProjects.add( project );
605 		
606 		return availableProjects;
607 	}
608 
609 	public Project openProject( Project project ) throws SoapUIException
610 	{
611 		return reloadProject( project );
612 	}
613 	
614 	public String getId()
615 	{
616 		return String.valueOf( hashCode() );
617 	}
618    
619    public List<? extends ModelItem> getChildren()
620    {
621       return getProjectList();
622    }
623 
624 	public ModelItem getParent()
625 	{
626 		return null;
627 	}
628 
629 	public void inspectProjects() {
630 		for( int cnt = 0 ; cnt < projectList.size(); cnt ++) {
631 			Project project = projectList.get(cnt);
632 			if( project.isOpen())
633 				project.inspect();
634 		}
635 	}
636 
637 	public String getProjectPassword(String name) {
638 			return projectOptions.get(name);
639 	}
640 
641 	public void clearProjectPassword(String name) {
642 		projectOptions.remove(name);
643 	}
644 
645 }