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