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 fireProjectAdded( Project project )
459 	{
460 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
461 		{
462 			WorkspaceListener listener = iter.next();
463 			listener.projectAdded( project );
464 		}
465 	}
466 
467 	private void fireWorkspaceSwitching()
468 	{
469 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
470 		{
471 			WorkspaceListener listener = iter.next();
472 			listener.workspaceSwitching( this );
473 		}
474 	}
475 
476 	private void fireWorkspaceSwitched()
477 	{
478 		for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
479 		{
480 			WorkspaceListener listener = iter.next();
481 			listener.workspaceSwitched( this );
482 		}
483 	}
484 
485 	private String createProjectFileName( String name )
486 	{
487 		return name + "-soapui-project.xml"; //$NON-NLS-1$
488 	}
489 
490 	public void removeProject( Project project )
491 	{
492 		int ix = projectList.indexOf( project );
493 		if( ix == -1 )
494 			throw new RuntimeException( "Project [" + project.getName() + "] not available in workspace for removal" );
495 
496 		projectList.remove( ix );
497 
498 		try
499 		{
500 			fireProjectRemoved( project );
501 		}
502 		finally
503 		{
504 			project.release();
505 			// workspaceConfig.getSoapuiWorkspace().removeProject( ix );
506 		}
507 	}
508 
509 	public Project reloadProject( Project project ) throws SoapUIException
510 	{
511 		int ix = projectList.indexOf( project );
512 		if( ix == -1 )
513 			throw new RuntimeException( "Project [" + project.getName() //$NON-NLS-1$
514 					+ "] not available in workspace for reload" ); //$NON-NLS-1$
515 
516 		projectList.remove( ix );
517 		fireProjectRemoved( project );
518 
519 		String tempName = project.getName();
520 		project.release();
521 		project = ( WsdlProject )ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( project.getPath(), this,
522 				false, true, tempName, null );
523 		projectList.add( ix, project );
524 
525 		fireProjectAdded( project );
526 
527 		return project;
528 	}
529 
530 	private void fireProjectRemoved( Project project )
531 	{
532 		WorkspaceListener[] listenerArray = listeners.toArray( new WorkspaceListener[listeners.size()] );
533 		for( int c = 0; c < listenerArray.length; c++ )
534 		{
535 			listenerArray[c].projectRemoved( project );
536 		}
537 	}
538 
539 	public ImageIcon getIcon()
540 	{
541 		return workspaceIcon;
542 	}
543 
544 	public Settings getSettings()
545 	{
546 		return settings;
547 	}
548 
549 	public int getIndexOfProject( Project project )
550 	{
551 		return projectList.indexOf( project );
552 	}
553 
554 	public String getPath()
555 	{
556 		return path;
557 	}
558 
559 	public String getProjectRoot()
560 	{
561 		return workspaceConfig.getSoapuiWorkspace().getProjectRoot();
562 	}
563 
564 	public void setProjectRoot( String workspaceRoot )
565 	{
566 		workspaceConfig.getSoapuiWorkspace().setProjectRoot( workspaceRoot );
567 	}
568 
569 	public void release()
570 	{
571 		settings.release();
572 
573 		for( Project project : projectList )
574 			project.release();
575 	}
576 
577 	public List<? extends Project> getProjectList()
578 	{
579 		return projectList;
580 	}
581 
582 	public String getDescription()
583 	{
584 		return workspaceConfig.getSoapuiWorkspace().getDescription();
585 	}
586 
587 	public WsdlProject importRemoteProject( String url ) throws SoapUIException
588 	{
589 		// WsdlProject project = new WsdlProject( url, this, false );
590 		WsdlProject project = ( WsdlProject )ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( url, this,
591 				false );
592 		projectList.add( project );
593 		fireProjectAdded( project );
594 
595 		resolveProject( project );
596 
597 		save( true );
598 
599 		return project;
600 	}
601 
602 	public void closeProject( Project project )
603 	{
604 		int oldProjectEncrypt = ( ( WsdlProject )project ).getEncrypted();
605 		int ix = projectList.indexOf( project );
606 		if( ix == -1 )
607 			throw new RuntimeException( "Project [" + project.getName() + "] not available in workspace for close" );
608 
609 		projectList.remove( ix );
610 		fireProjectRemoved( project );
611 
612 		String name = project.getName();
613 		project.release();
614 
615 		try
616 		{
617 			// project = new WsdlProject( project.getPath(), this, false, false,
618 			// name, null );
619 			project = ProjectFactoryRegistry.getProjectFactory( WsdlProjectFactory.WSDL_TYPE ).createNew(
620 					project.getPath(), this, false, false, name, null );
621 			( ( WsdlProject )project ).setEncrypted( oldProjectEncrypt );
622 			projectList.add( ix, project );
623 			fireProjectAdded( project );
624 		}
625 		catch( Exception e )
626 		{
627 			UISupport.showErrorMessage( messages.get( "FailedToCloseProject.Error", name ) + e.getMessage() );
628 			SoapUI.logError( e );
629 		}
630 	}
631 
632 	public List<Project> getOpenProjectList()
633 	{
634 		List<Project> availableProjects = new ArrayList<Project>();
635 
636 		for( Project project : projectList )
637 			if( project.isOpen() )
638 				availableProjects.add( project );
639 
640 		return availableProjects;
641 	}
642 
643 	public Project openProject( Project project ) throws SoapUIException
644 	{
645 		return reloadProject( project );
646 	}
647 
648 	public String getId()
649 	{
650 		return String.valueOf( hashCode() );
651 	}
652 
653 	public List<? extends ModelItem> getChildren()
654 	{
655 		return getProjectList();
656 	}
657 
658 	public ModelItem getParent()
659 	{
660 		return null;
661 	}
662 
663 	public void inspectProjects()
664 	{
665 		for( int cnt = 0; cnt < projectList.size(); cnt++ )
666 		{
667 			Project project = projectList.get( cnt );
668 			if( project.isOpen() )
669 				project.inspect();
670 		}
671 	}
672 
673 	public String getProjectPassword( String name )
674 	{
675 		return projectOptions.get( name );
676 	}
677 
678 	public void clearProjectPassword( String name )
679 	{
680 		projectOptions.remove( name );
681 	}
682 
683 }