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.wsdl;
14  
15  import java.beans.PropertyChangeEvent;
16  import java.beans.PropertyChangeListener;
17  import java.io.BufferedReader;
18  import java.io.BufferedWriter;
19  import java.io.File;
20  import java.io.FileNotFoundException;
21  import java.io.FileOutputStream;
22  import java.io.FileReader;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.net.MalformedURLException;
26  import java.net.URL;
27  import java.security.GeneralSecurityException;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  
36  import javax.swing.ImageIcon;
37  import javax.xml.namespace.QName;
38  
39  import org.apache.commons.ssl.OpenSSL;
40  import org.apache.log4j.Logger;
41  import org.apache.xmlbeans.XmlError;
42  import org.apache.xmlbeans.XmlException;
43  import org.apache.xmlbeans.XmlObject;
44  import org.apache.xmlbeans.XmlOptions;
45  
46  import com.eviware.soapui.SoapUI;
47  import com.eviware.soapui.config.InterfaceConfig;
48  import com.eviware.soapui.config.MockServiceConfig;
49  import com.eviware.soapui.config.MockServiceDocumentConfig;
50  import com.eviware.soapui.config.ProjectConfig;
51  import com.eviware.soapui.config.SoapuiProjectDocumentConfig;
52  import com.eviware.soapui.config.TestSuiteConfig;
53  import com.eviware.soapui.config.TestSuiteDocumentConfig;
54  import com.eviware.soapui.config.TestSuiteRunTypesConfig;
55  import com.eviware.soapui.config.TestSuiteRunTypesConfig.Enum;
56  import com.eviware.soapui.impl.WorkspaceImpl;
57  import com.eviware.soapui.impl.WsdlInterfaceFactory;
58  import com.eviware.soapui.impl.rest.support.RestRequestConverter.RestConversionException;
59  import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
60  import com.eviware.soapui.impl.support.AbstractInterface;
61  import com.eviware.soapui.impl.wsdl.endpoint.DefaultEndpointStrategy;
62  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
63  import com.eviware.soapui.impl.wsdl.support.PathUtils;
64  import com.eviware.soapui.impl.wsdl.support.wsdl.UrlWsdlLoader;
65  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlLoader;
66  import com.eviware.soapui.impl.wsdl.support.wss.DefaultWssContainer;
67  import com.eviware.soapui.impl.wsdl.testcase.WsdlProjectRunner;
68  import com.eviware.soapui.model.ModelItem;
69  import com.eviware.soapui.model.iface.Interface;
70  import com.eviware.soapui.model.mock.MockService;
71  import com.eviware.soapui.model.project.EndpointStrategy;
72  import com.eviware.soapui.model.project.Project;
73  import com.eviware.soapui.model.project.ProjectListener;
74  import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
75  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
76  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
77  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
78  import com.eviware.soapui.model.settings.Settings;
79  import com.eviware.soapui.model.support.ModelSupport;
80  import com.eviware.soapui.model.testsuite.ProjectRunContext;
81  import com.eviware.soapui.model.testsuite.ProjectRunListener;
82  import com.eviware.soapui.model.testsuite.ProjectRunner;
83  import com.eviware.soapui.model.testsuite.TestRunnable;
84  import com.eviware.soapui.model.testsuite.TestSuite;
85  import com.eviware.soapui.model.testsuite.TestSuite.TestSuiteRunType;
86  import com.eviware.soapui.settings.ProjectSettings;
87  import com.eviware.soapui.settings.UISettings;
88  import com.eviware.soapui.settings.WsdlSettings;
89  import com.eviware.soapui.support.SoapUIException;
90  import com.eviware.soapui.support.StringUtils;
91  import com.eviware.soapui.support.Tools;
92  import com.eviware.soapui.support.UISupport;
93  import com.eviware.soapui.support.resolver.ResolveContext;
94  import com.eviware.soapui.support.resolver.ResolveDialog;
95  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
96  import com.eviware.soapui.support.scripting.SoapUIScriptEngineRegistry;
97  import com.eviware.soapui.support.types.StringToObjectMap;
98  
99  /***
100  * WSDL project implementation
101  * 
102  * @author Ole.Matzura
103  */
104 
105 public class WsdlProject extends AbstractTestPropertyHolderWsdlModelItem<ProjectConfig> implements Project,
106 		PropertyExpansionContainer, PropertyChangeListener, TestRunnable
107 {
108 	public final static String AFTER_LOAD_SCRIPT_PROPERTY = WsdlProject.class.getName() + "@setupScript";
109 	public final static String BEFORE_SAVE_SCRIPT_PROPERTY = WsdlProject.class.getName() + "@tearDownScript";
110 	public final static String RESOURCE_ROOT_PROPERTY = WsdlProject.class.getName() + "@resourceRoot";
111 
112 	private WorkspaceImpl workspace;
113 	protected String path;
114 	protected List<AbstractInterface<?>> interfaces = new ArrayList<AbstractInterface<?>>();
115 	protected List<WsdlTestSuite> testSuites = new ArrayList<WsdlTestSuite>();
116 	protected List<WsdlMockService> mockServices = new ArrayList<WsdlMockService>();
117 	private Set<ProjectListener> projectListeners = new HashSet<ProjectListener>();
118 	protected SoapuiProjectDocumentConfig projectDocument;
119 	private ImageIcon disabledIcon;
120 	private ImageIcon closedIcon;
121 	private ImageIcon remoteIcon;
122 	private ImageIcon openEncyptedIcon;
123 	protected EndpointStrategy endpointStrategy = new DefaultEndpointStrategy();
124 	protected long lastModified;
125 	private boolean remote;
126 	private boolean open = true;
127 	private boolean disabled;
128 
129 	private SoapUIScriptEngine afterLoadScriptEngine;
130 	private SoapUIScriptEngine beforeSaveScriptEngine;
131 	private PropertyExpansionContext context = new DefaultPropertyExpansionContext( this );
132 	protected DefaultWssContainer wssContainer;
133 	private String projectPassword = null;
134 	private String hermesConfig;
135 	private boolean wrongPasswordSupplied;
136 
137 	/*
138 	 * 3 state flag: 1. 0 - project not encrypted 2. 1 - encrypted , good
139 	 * password, means that it could be successfully decrypted 3. -1 - encrypted,
140 	 * but with bad password or no password.
141 	 */
142 
143 	protected int encrypted;
144 	private ImageIcon closedEncyptedIcon;
145 	private SoapUIScriptEngine afterRunScriptEngine;
146 	private SoapUIScriptEngine beforeRunScriptEngine;
147 	private Set<ProjectRunListener> runListeners = new HashSet<ProjectRunListener>();
148 
149 	protected final static Logger log = Logger.getLogger( WsdlProject.class );
150 
151 	public WsdlProject() throws XmlException, IOException, SoapUIException
152 	{
153 		this( ( WorkspaceImpl )null );
154 	}
155 
156 	public WsdlProject( String path ) throws XmlException, IOException, SoapUIException
157 	{
158 		this( path, ( WorkspaceImpl )null );
159 	}
160 
161 	public WsdlProject( String projectFile, String projectPassword )
162 	{
163 		this( projectFile, null, true, true, null, projectPassword );
164 	}
165 
166 	public WsdlProject( WorkspaceImpl workspace )
167 	{
168 		this( null, workspace, true );
169 	}
170 
171 	public WsdlProject( String path, WorkspaceImpl workspace )
172 	{
173 		this( path, workspace, true );
174 	}
175 
176 	public WsdlProject( String path, WorkspaceImpl workspace, boolean create )
177 	{
178 		this( path, workspace, create, true, null, null );
179 	}
180 
181 	public WsdlProject( String path, WorkspaceImpl workspace, boolean create, boolean open, String tempName,
182 			String projectPassword )
183 	{
184 		super( null, workspace, "/project.gif" );
185 
186 		this.workspace = workspace;
187 		this.path = path;
188 		this.projectPassword = projectPassword;
189 
190 		for( ProjectListener listener : SoapUI.getListenerRegistry().getListeners( ProjectListener.class ) )
191 		{
192 			addProjectListener( listener );
193 		}
194 
195 		for( ProjectRunListener listener : SoapUI.getListenerRegistry().getListeners( ProjectRunListener.class ) )
196 		{
197 			addProjectRunListener( listener );
198 		}
199 
200 		try
201 		{
202 			if( path != null && open )
203 			{
204 				File file = new File( path.trim() );
205 				if( file.exists() )
206 				{
207 					try
208 					{
209 						loadProject( new URL( "file:" + file.getAbsolutePath() ) );
210 						lastModified = file.lastModified();
211 					}
212 					catch( MalformedURLException e )
213 					{
214 						SoapUI.logError( e );
215 						disabled = true;
216 					}
217 				}
218 				else
219 				{
220 					try
221 					{
222 						if( !PathUtils.isHttpPath( path ) )
223 							SoapUI.log.info( "File [" + file.getAbsolutePath() + "] does not exist, trying URL instead" );
224 
225 						remote = true;
226 						loadProject( new URL( path ) );
227 					}
228 					catch( MalformedURLException e )
229 					{
230 						SoapUI.logError( e );
231 						disabled = true;
232 					}
233 				}
234 			}
235 		}
236 		catch( SoapUIException e )
237 		{
238 			SoapUI.logError( e );
239 			disabled = true;
240 		}
241 		finally
242 		{
243 			closedIcon = UISupport.createImageIcon( "/closedProject.gif" );
244 			remoteIcon = UISupport.createImageIcon( "/remoteProject.gif" );
245 			disabledIcon = UISupport.createImageIcon( "/disabledProject.gif" );
246 			openEncyptedIcon = UISupport.createImageIcon( "/openEncryptedProject.gif" );
247 			closedEncyptedIcon = UISupport.createImageIcon( "/closedEncryptedProject.gif" );
248 
249 			this.open = open && !disabled && ( this.encrypted != -1 );
250 
251 			if( projectDocument == null )
252 			{
253 				projectDocument = SoapuiProjectDocumentConfig.Factory.newInstance();
254 				setConfig( projectDocument.addNewSoapuiProject() );
255 				if( tempName != null || path != null )
256 					getConfig().setName( StringUtils.isNullOrEmpty( tempName ) ? getNameFromPath() : tempName );
257 
258 				setPropertiesConfig( getConfig().addNewProperties() );
259 				wssContainer = new DefaultWssContainer( this, getConfig().addNewWssContainer() );
260 				// setResourceRoot("${projectDir}");
261 			}
262 
263 			if( getConfig() != null )
264 			{
265 				endpointStrategy.init( this );
266 			}
267 			if( getSettings() != null )
268 			{
269 				setProjectRoot( path );
270 			}
271 
272 			addPropertyChangeListener( this );
273 		}
274 	}
275 
276 	public boolean isRemote()
277 	{
278 		return remote;
279 	}
280 
281 	public void loadProject( URL file ) throws SoapUIException
282 	{
283 		try
284 		{
285 			UISupport.setHourglassCursor();
286 
287 			UrlWsdlLoader loader = new UrlWsdlLoader( file.toString(), this );
288 			loader.setUseWorker( false );
289 			projectDocument = SoapuiProjectDocumentConfig.Factory.parse( loader.load() );
290 
291 			// see if there is encoded data
292 			this.encrypted = checkForEncodedData( projectDocument.getSoapuiProject() );
293 
294 			setConfig( projectDocument.getSoapuiProject() );
295 
296 			// removed cached definitions if caching is disabled
297 			if( !getSettings().getBoolean( WsdlSettings.CACHE_WSDLS ) )
298 			{
299 				removeDefinitionCaches( projectDocument );
300 			}
301 
302 			log.info( "Loaded project from [" + file.toString() + "]" );
303 
304 			try
305 			{
306 				int majorVersion = Integer
307 						.parseInt( projectDocument.getSoapuiProject().getSoapuiVersion().split( "//." )[0] );
308 				if( majorVersion > Integer.parseInt( SoapUI.SOAPUI_VERSION.split( "//." )[0] ) )
309 					log.warn( "Project '" + projectDocument.getSoapuiProject().getName() + "' is from a newer version ("
310 							+ projectDocument.getSoapuiProject().getSoapuiVersion() + ") of soapUI than this ("
311 							+ SoapUI.SOAPUI_VERSION + ") and parts of it may be incompatible or incorrect. "
312 							+ "Saving this project with this version of soapUI may cause it to function differently." );
313 			}
314 			catch( Exception e )
315 			{
316 			}
317 
318 			List<InterfaceConfig> interfaceConfigs = getConfig().getInterfaceList();
319 			for( InterfaceConfig config : interfaceConfigs )
320 			{
321 				AbstractInterface<?> iface = InterfaceFactoryRegistry.build( this, config );
322 				interfaces.add( iface );
323 			}
324 
325 			List<TestSuiteConfig> testSuiteConfigs = getConfig().getTestSuiteList();
326 			for( TestSuiteConfig config : testSuiteConfigs )
327 			{
328 				testSuites.add( buildTestSuite( config ) );
329 			}
330 
331 			List<MockServiceConfig> mockServiceConfigs = getConfig().getMockServiceList();
332 			for( MockServiceConfig config : mockServiceConfigs )
333 			{
334 				mockServices.add( new WsdlMockService( this, config ) );
335 			}
336 
337 			if( !getConfig().isSetWssContainer() )
338 				getConfig().addNewWssContainer();
339 
340 			wssContainer = new DefaultWssContainer( this, getConfig().getWssContainer() );
341 
342 			endpointStrategy.init( this );
343 
344 			if( !getConfig().isSetProperties() )
345 				getConfig().addNewProperties();
346 
347 			if( !getConfig().isSetAbortOnError() )
348 				getConfig().setAbortOnError( false );
349 
350 			// if( !getConfig().isSetFailOnErrors() )
351 			// getConfig().setFailOnErrors( true );
352 
353 			if( !getConfig().isSetRunType() )
354 				getConfig().setRunType( TestSuiteRunTypesConfig.SEQUENTIAL );
355 
356 			setPropertiesConfig( getConfig().getProperties() );
357 			afterLoad();
358 		}
359 		catch( Exception e )
360 		{
361 			if( e instanceof XmlException )
362 			{
363 				XmlException xe = ( XmlException )e;
364 				XmlError error = xe.getError();
365 				if( error != null )
366 					System.err.println( "Error at line " + error.getLine() + ", column " + error.getColumn() );
367 			}
368 
369 			if( e instanceof RestConversionException )
370 			{
371 				log.error( "Project file needs to be updated manually, please reload the project." );
372 				throw new SoapUIException( "Failed to load project from file [" + file.toString() + "]", e );
373 			}
374 
375 			e.printStackTrace();
376 			throw new SoapUIException( "Failed to load project from file [" + file.toString() + "]", e );
377 		}
378 		finally
379 		{
380 			UISupport.resetCursor();
381 		}
382 	}
383 
384 	protected WsdlTestSuite buildTestSuite( TestSuiteConfig config )
385 	{
386 		return new WsdlTestSuite( this, config );
387 	}
388 
389 	public boolean isWrongPasswordSupplied()
390 	{
391 		return wrongPasswordSupplied;
392 	}
393 
394 	/***
395 	 * Decode encrypted data and restore user/pass
396 	 * 
397 	 * @param soapuiProject
398 	 * @return 0 - not encrypted, 1 - successfull decryption , -1 error while
399 	 *         decrypting, bad password, no password.
400 	 * @throws IOException
401 	 * @throws GeneralSecurityException
402 	 * @author robert nemet
403 	 */
404 	protected int checkForEncodedData( ProjectConfig soapuiProject ) throws IOException, GeneralSecurityException
405 	{
406 
407 		byte[] encryptedContent = soapuiProject.getEncryptedContent();
408 		char[] password = null;
409 
410 		// no encrypted data then go back
411 		if( encryptedContent == null || encryptedContent.length == 0 )
412 			return 0;
413 
414 		String projectPassword = null;
415 		if( workspace != null )
416 		{
417 			projectPassword = workspace.getProjectPassword( soapuiProject.getName() );
418 		}
419 		else
420 		{
421 			projectPassword = this.projectPassword;
422 		}
423 		if( projectPassword == null )
424 		{
425 			password = UISupport.promptPassword( "Enter Password:", soapuiProject.getName() );
426 		}
427 		else
428 		{
429 			password = projectPassword.toCharArray();
430 		}
431 		byte[] data = null;
432 		// no pass go back.
433 		if( password == null )
434 		{
435 			return -1;
436 		}
437 
438 		try
439 		{
440 			data = OpenSSL.decrypt( "des3", password, encryptedContent );
441 		}
442 		catch( Exception e )
443 		{
444 			e.printStackTrace();
445 			return -1;
446 		}
447 
448 		String decryptedData = new String( data, "UTF-8" );
449 
450 		if( decryptedData != null )
451 		{
452 			if( decryptedData.length() > 0 )
453 			{
454 				try
455 				{
456 					projectDocument.getSoapuiProject().set( XmlObject.Factory.parse( decryptedData ) );
457 					wrongPasswordSupplied = false;
458 				}
459 				catch( XmlException e )
460 				{
461 					UISupport.showErrorMessage( "Wrong password. Project needs to be reloaded." );
462 					wrongPasswordSupplied = true;
463 					getWorkspace().clearProjectPassword( soapuiProject.getName() );
464 					return -1;
465 				}
466 			}
467 		}
468 		else
469 		{
470 			UISupport.showErrorMessage( "Wrong project password" );
471 			wrongPasswordSupplied = true;
472 			getWorkspace().clearProjectPassword( soapuiProject.getName() );
473 			return -1;
474 		}
475 		projectDocument.getSoapuiProject().setEncryptedContent( null );
476 		return 1;
477 	}
478 
479 	@Override
480 	public void afterLoad()
481 	{
482 		super.afterLoad();
483 
484 		try
485 		{
486 			ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
487 
488 			for( int c = 0; c < a.length; c++ )
489 			{
490 				a[c].afterLoad( this );
491 			}
492 
493 			runAfterLoadScript();
494 		}
495 		catch( Exception e )
496 		{
497 			SoapUI.logError( e );
498 		}
499 	}
500 
501 	protected void setProjectRoot( String path )
502 	{
503 		if( path != null && projectDocument != null )
504 		{
505 			int ix = path.lastIndexOf( File.separatorChar );
506 			if( ix > 0 )
507 				getSettings().setString( ProjectSettings.PROJECT_ROOT, path.substring( 0, ix ) );
508 		}
509 	}
510 
511 	public void setResourceRoot( String resourceRoot )
512 	{
513 		String old = getResourceRoot();
514 
515 		getConfig().setResourceRoot( resourceRoot );
516 		notifyPropertyChanged( RESOURCE_ROOT_PROPERTY, old, resourceRoot );
517 	}
518 
519 	public String getResourceRoot()
520 	{
521 		if( !getConfig().isSetResourceRoot() )
522 			getConfig().setResourceRoot( "" );
523 
524 		return getConfig().getResourceRoot();
525 	}
526 
527 	@Override
528 	public ImageIcon getIcon()
529 	{
530 		if( isDisabled() )
531 			return disabledIcon;
532 		else if( getEncrypted() != 0 )
533 		{
534 			if( isOpen() )
535 			{
536 				return openEncyptedIcon;
537 			}
538 			else
539 			{
540 				return closedEncyptedIcon;
541 			}
542 		}
543 		else if( !isOpen() )
544 			return closedIcon;
545 		else if( isRemote() )
546 			return remoteIcon;
547 		else
548 			return super.getIcon();
549 	}
550 
551 	private String getNameFromPath()
552 	{
553 		int ix = path.lastIndexOf( isRemote() ? '/' : File.separatorChar );
554 		String name = ix == -1 ? path : path.substring( ix + 1 );
555 		return name;
556 	}
557 
558 	@Override
559 	public String getDescription()
560 	{
561 		if( isOpen() )
562 			return super.getDescription();
563 
564 		String name = getName();
565 
566 		if( isDisabled() )
567 			name += " - disabled [" + getPath() + "]";
568 		else
569 			name += " - closed [" + getPath() + "]";
570 
571 		return name;
572 	}
573 
574 	public WorkspaceImpl getWorkspace()
575 	{
576 		return workspace;
577 	}
578 
579 	public AbstractInterface<?> getInterfaceAt( int index )
580 	{
581 		return interfaces.get( index );
582 	}
583 
584 	public AbstractInterface<?> getInterfaceByName( String interfaceName )
585 	{
586 		return ( AbstractInterface<?> )getWsdlModelItemByName( interfaces, interfaceName );
587 	}
588 
589 	public AbstractInterface<?> getInterfaceByTechnicalId( String technicalId )
590 	{
591 		for( int c = 0; c < getInterfaceCount(); c++ )
592 		{
593 			if( getInterfaceAt( c ).getTechnicalId().equals( technicalId ) )
594 				return getInterfaceAt( c );
595 		}
596 
597 		return null;
598 	}
599 
600 	public int getInterfaceCount()
601 	{
602 		return interfaces.size();
603 	}
604 
605 	public String getPath()
606 	{
607 		return path;
608 	}
609 
610 	public boolean save() throws IOException
611 	{
612 		return save( null );
613 	}
614 
615 	public boolean save( String folder ) throws IOException
616 	{
617 		if( !isOpen() || isDisabled() || isRemote() )
618 			return true;
619 
620 		if( path == null || isRemote() )
621 		{
622 			path = StringUtils.createFileName2( getName(), '-' ) + "-soapui-project.xml";
623 			if( folder != null )
624 			{
625 				path = folder + File.separatorChar + path;
626 			}
627 
628 			File file = null;
629 
630 			while( file == null
631 					|| ( file.exists() && !UISupport.confirm( "File [" + file.getName() + "] exists, overwrite?",
632 							"Overwrite File?" ) ) )
633 			{
634 				file = UISupport.getFileDialogs().saveAs( this, "Save project " + getName(), ".xml", "XML Files (*.xml)",
635 						new File( path ) );
636 				if( file == null )
637 					return false;
638 			}
639 
640 			path = file.getAbsolutePath();
641 		}
642 
643 		File projectFile = new File( path );
644 
645 		while( projectFile.exists() && !projectFile.canWrite() )
646 		{
647 			if( UISupport.confirm( "Project file [" + path + "] can not be written to, save to new file?", "Save Project" ) )
648 			{
649 				projectFile = UISupport.getFileDialogs().saveAs( this, "Save project " + getName(), ".xml",
650 						"XML Files (*.xml)", projectFile );
651 
652 				if( projectFile == null )
653 					return false;
654 
655 				path = projectFile.getAbsolutePath();
656 			}
657 			else
658 				return false;
659 		}
660 
661 		// check modified
662 		if( projectFile.exists() && lastModified != 0 && lastModified < projectFile.lastModified() )
663 		{
664 			if( !UISupport.confirm( "Project file for [" + getName() + "] has been modified externally, overwrite?",
665 					"Save Project" ) )
666 				return false;
667 		}
668 
669 		if( projectFile.exists() && getSettings().getBoolean( UISettings.CREATE_BACKUP ) )
670 		{
671 			createBackup( projectFile );
672 		}
673 
674 		return saveIn( projectFile );
675 	}
676 
677 	public boolean saveBackup() throws IOException
678 	{
679 		File projectFile;
680 		if( path == null || isRemote() )
681 		{
682 			projectFile = new File( StringUtils.createFileName2( getName(), '-' ) + "-soapui-project.xml" );
683 		}
684 		else
685 		{
686 			projectFile = new File( path );
687 		}
688 		File backupFile = getBackupFile( projectFile );
689 		return saveIn( backupFile );
690 	}
691 
692 	public boolean saveIn( File projectFile ) throws IOException
693 	{
694 		long size = 0;
695 
696 		beforeSave();
697 		// work with copy beacuse we do not want to change working project while
698 		// working with it
699 		// if user choose save project, save all etc.
700 		SoapuiProjectDocumentConfig projectDocument = ( SoapuiProjectDocumentConfig )this.projectDocument.copy();
701 
702 		// check for caching
703 		if( !getSettings().getBoolean( WsdlSettings.CACHE_WSDLS ) )
704 		{
705 			// no caching -> create copy and remove definition cachings
706 			removeDefinitionCaches( projectDocument );
707 		}
708 
709 		// remove project root
710 		XmlBeansSettingsImpl tempSettings = new XmlBeansSettingsImpl( this, null, projectDocument.getSoapuiProject()
711 				.getSettings() );
712 		tempSettings.clearSetting( ProjectSettings.PROJECT_ROOT );
713 
714 		// check for encryption
715 		String passwordForEncryption = getSettings().getString( ProjectSettings.SHADOW_PASSWORD, null );
716 
717 		// if it has encryptedContend that means it is not decrypted corectly( bad
718 		// password, etc ), so do not encrypt it again.
719 		if( projectDocument.getSoapuiProject().getEncryptedContent() == null )
720 		{
721 			if( passwordForEncryption != null )
722 			{
723 				if( passwordForEncryption.length() > 1 )
724 				{
725 					// we have password so do encryption
726 					try
727 					{
728 						String data = getConfig().xmlText();
729 						byte[] encrypted = OpenSSL.encrypt( "des3", passwordForEncryption.toCharArray(), data.getBytes() );
730 						projectDocument.getSoapuiProject().setEncryptedContent( encrypted );
731 						projectDocument.getSoapuiProject().setInterfaceArray( null );
732 						projectDocument.getSoapuiProject().setTestSuiteArray( null );
733 						projectDocument.getSoapuiProject().setMockServiceArray( null );
734 						projectDocument.getSoapuiProject().unsetWssContainer();
735 						projectDocument.getSoapuiProject().unsetSettings();
736 						projectDocument.getSoapuiProject().unsetProperties();
737 
738 					}
739 					catch( GeneralSecurityException e )
740 					{
741 						UISupport.showErrorMessage( "Encryption Error" );
742 					}
743 				}
744 				else
745 				{
746 					// no password no encryption.
747 					projectDocument.getSoapuiProject().setEncryptedContent( null );
748 				}
749 			}
750 		}
751 		// end of encryption.
752 
753 		XmlOptions options = new XmlOptions();
754 		if( SoapUI.getSettings().getBoolean( WsdlSettings.PRETTY_PRINT_PROJECT_FILES ) )
755 			options.setSavePrettyPrint();
756 
757 		projectDocument.getSoapuiProject().setSoapuiVersion( SoapUI.SOAPUI_VERSION );
758 
759 		try
760 		{
761 			File tempFile = File.createTempFile( "project-temp-", ".xml", projectFile.getParentFile() );
762 
763 			// save once to make sure it can be saved
764 			FileOutputStream tempOut = new FileOutputStream( tempFile );
765 			projectDocument.save( tempOut, options );
766 			tempOut.close();
767 
768 			if( getSettings().getBoolean( UISettings.LINEBREAK ) )
769 			{
770 				normalizeLineBreak( projectFile, tempFile );
771 			}
772 			else
773 			{
774 				// now save it for real
775 				FileOutputStream projectOut = new FileOutputStream( projectFile );
776 				projectDocument.save( projectOut, options );
777 				projectOut.close();
778 				// delete tempFile here so we have it as backup in case second save
779 				// fails
780 				if( !tempFile.delete() )
781 				{
782 					SoapUI.getErrorLog().warn( "Failed to delete temporary project file; " + tempFile.getAbsolutePath() );
783 					tempFile.deleteOnExit();
784 				}
785 			}
786 			size = projectFile.length();
787 		}
788 		catch( Throwable t )
789 		{
790 			SoapUI.logError( t );
791 			UISupport.showErrorMessage( "Failed to save project [" + getName() + "]: " + t.toString() );
792 			return false;
793 		}
794 
795 		lastModified = projectFile.lastModified();
796 		log.info( "Saved project [" + getName() + "] to [" + projectFile.getAbsolutePath() + " - " + size + " bytes" );
797 		setProjectRoot( getPath() );
798 		return true;
799 	}
800 
801 	private static void normalizeLineBreak( File target, File tmpFile )
802 	{
803 		try
804 		{
805 			FileReader fr = new FileReader( tmpFile );
806 			BufferedReader in = new BufferedReader( fr );
807 			FileWriter fw = new FileWriter( target );
808 			BufferedWriter out = new BufferedWriter( fw );
809 			String line = "";
810 			while( ( line = in.readLine() ) != null )
811 			{
812 				out.write( line );
813 				out.newLine();
814 				out.flush();
815 			}
816 			out.close();
817 			fw.close();
818 			in.close();
819 			fr.close();
820 		}
821 		catch( FileNotFoundException e )
822 		{
823 			// TODO Auto-generated catch block
824 			e.printStackTrace();
825 		}
826 		catch( IOException e )
827 		{
828 			// TODO Auto-generated catch block
829 			e.printStackTrace();
830 		}
831 
832 		if( !tmpFile.delete() )
833 		{
834 			SoapUI.getErrorLog().warn( "Failed to delete temporary file: " + tmpFile.getAbsolutePath() );
835 			tmpFile.deleteOnExit();
836 		}
837 	}
838 
839 	public void beforeSave()
840 	{
841 		try
842 		{
843 			ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
844 
845 			for( int c = 0; c < a.length; c++ )
846 			{
847 				a[c].beforeSave( this );
848 			}
849 
850 			runBeforeSaveScript();
851 		}
852 		catch( Exception e )
853 		{
854 			SoapUI.logError( e );
855 		}
856 
857 		// notify
858 		for( AbstractInterface<?> iface : interfaces )
859 			iface.beforeSave();
860 
861 		for( WsdlTestSuite testSuite : testSuites )
862 			testSuite.beforeSave();
863 
864 		for( WsdlMockService mockService : mockServices )
865 			mockService.beforeSave();
866 
867 		endpointStrategy.onSave();
868 	}
869 
870 	protected void createBackup( File projectFile ) throws IOException
871 	{
872 		File backupFile = getBackupFile( projectFile );
873 		log.info( "Backing up [" + projectFile + "] to [" + backupFile + "]" );
874 		Tools.copyFile( projectFile, backupFile, true );
875 	}
876 
877 	protected File getBackupFile( File projectFile )
878 	{
879 		String backupFolderName = getSettings().getString( UISettings.BACKUP_FOLDER, "" );
880 
881 		File backupFolder = new File( backupFolderName );
882 		if( !backupFolder.isAbsolute() )
883 		{
884 			backupFolder = new File( projectFile.getParentFile(), backupFolderName );
885 		}
886 
887 		if( !backupFolder.exists() )
888 			backupFolder.mkdirs();
889 
890 		File backupFile = new File( backupFolder, projectFile.getName() + ".backup" );
891 		return backupFile;
892 	}
893 
894 	protected void removeDefinitionCaches( SoapuiProjectDocumentConfig config )
895 	{
896 		for( InterfaceConfig ifaceConfig : config.getSoapuiProject().getInterfaceList() )
897 		{
898 			if( ifaceConfig.isSetDefinitionCache() )
899 			{
900 				log.info( "Removing definition cache from interface [" + ifaceConfig.getName() + "]" );
901 				ifaceConfig.unsetDefinitionCache();
902 			}
903 		}
904 	}
905 
906 	public AbstractInterface<?> addNewInterface( String name, String type )
907 	{
908 		AbstractInterface<?> iface = ( AbstractInterface<?> )InterfaceFactoryRegistry.createNew( this, type, name );
909 		if( iface != null )
910 		{
911 			iface.getConfig().setType( type );
912 
913 			interfaces.add( iface );
914 			fireInterfaceAdded( iface );
915 		}
916 
917 		return iface;
918 	}
919 
920 	public void addProjectListener( ProjectListener listener )
921 	{
922 		projectListeners.add( listener );
923 	}
924 
925 	public void removeProjectListener( ProjectListener listener )
926 	{
927 		projectListeners.remove( listener );
928 	}
929 
930 	public void fireInterfaceAdded( AbstractInterface<?> iface )
931 	{
932 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
933 
934 		for( int c = 0; c < a.length; c++ )
935 		{
936 			a[c].interfaceAdded( iface );
937 		}
938 	}
939 
940 	public void fireInterfaceRemoved( AbstractInterface<?> iface )
941 	{
942 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
943 
944 		for( int c = 0; c < a.length; c++ )
945 		{
946 			a[c].interfaceRemoved( iface );
947 		}
948 	}
949 
950 	public void fireInterfaceUpdated( AbstractInterface<?> iface )
951 	{
952 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
953 
954 		for( int c = 0; c < a.length; c++ )
955 		{
956 			a[c].interfaceUpdated( iface );
957 		}
958 	}
959 
960 	public void fireTestSuiteAdded( WsdlTestSuite testSuite )
961 	{
962 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
963 
964 		for( int c = 0; c < a.length; c++ )
965 		{
966 			a[c].testSuiteAdded( testSuite );
967 		}
968 	}
969 
970 	private void fireTestSuiteMoved( WsdlTestSuite testCase, int ix, int offset )
971 	{
972 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
973 
974 		for( int c = 0; c < a.length; c++ )
975 		{
976 			a[c].testSuiteMoved( testCase, ix, offset );
977 		}
978 	}
979 
980 	public void fireTestSuiteRemoved( WsdlTestSuite testSuite )
981 	{
982 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
983 
984 		for( int c = 0; c < a.length; c++ )
985 		{
986 			a[c].testSuiteRemoved( testSuite );
987 		}
988 	}
989 
990 	public void fireMockServiceAdded( WsdlMockService mockService )
991 	{
992 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
993 
994 		for( int c = 0; c < a.length; c++ )
995 		{
996 			a[c].mockServiceAdded( mockService );
997 		}
998 	}
999 
1000 	public void fireMockServiceRemoved( WsdlMockService mockService )
1001 	{
1002 		ProjectListener[] a = projectListeners.toArray( new ProjectListener[projectListeners.size()] );
1003 
1004 		for( int c = 0; c < a.length; c++ )
1005 		{
1006 			a[c].mockServiceRemoved( mockService );
1007 		}
1008 	}
1009 
1010 	public void removeInterface( AbstractInterface<?> iface )
1011 	{
1012 		int ix = interfaces.indexOf( iface );
1013 		interfaces.remove( ix );
1014 		try
1015 		{
1016 			fireInterfaceRemoved( iface );
1017 		}
1018 		finally
1019 		{
1020 			iface.release();
1021 			getConfig().removeInterface( ix );
1022 		}
1023 	}
1024 
1025 	public void removeTestSuite( WsdlTestSuite testSuite )
1026 	{
1027 		int ix = testSuites.indexOf( testSuite );
1028 		testSuites.remove( ix );
1029 
1030 		try
1031 		{
1032 			fireTestSuiteRemoved( testSuite );
1033 		}
1034 		finally
1035 		{
1036 			testSuite.release();
1037 			getConfig().removeTestSuite( ix );
1038 		}
1039 	}
1040 
1041 	public boolean isDisabled()
1042 	{
1043 		return disabled;
1044 	}
1045 
1046 	public int getTestSuiteCount()
1047 	{
1048 		return testSuites.size();
1049 	}
1050 
1051 	public WsdlTestSuite getTestSuiteAt( int index )
1052 	{
1053 		return testSuites.get( index );
1054 	}
1055 
1056 	public WsdlTestSuite getTestSuiteByName( String testSuiteName )
1057 	{
1058 		return ( WsdlTestSuite )getWsdlModelItemByName( testSuites, testSuiteName );
1059 	}
1060 
1061 	public WsdlTestSuite addNewTestSuite( String name )
1062 	{
1063 		WsdlTestSuite testSuite = buildTestSuite( getConfig().addNewTestSuite() );
1064 		testSuite.setName( name );
1065 		testSuites.add( testSuite );
1066 		fireTestSuiteAdded( testSuite );
1067 
1068 		return testSuite;
1069 	}
1070 
1071 	public boolean isCacheDefinitions()
1072 	{
1073 		return getSettings().getBoolean( WsdlSettings.CACHE_WSDLS );
1074 	}
1075 
1076 	public void setCacheDefinitions( boolean cacheDefinitions )
1077 	{
1078 		getSettings().setBoolean( WsdlSettings.CACHE_WSDLS, cacheDefinitions );
1079 	}
1080 
1081 	public boolean saveAs( String fileName ) throws IOException
1082 	{
1083 		if( !isOpen() || isDisabled() )
1084 			return false;
1085 
1086 		String oldPath = path;
1087 		path = fileName;
1088 		boolean result = save();
1089 		if( !result )
1090 			path = oldPath;
1091 		else
1092 			remote = false;
1093 
1094 		setProjectRoot( path );
1095 
1096 		return result;
1097 	}
1098 
1099 	@Override
1100 	public void release()
1101 	{
1102 		super.release();
1103 
1104 		if( isOpen() )
1105 		{
1106 			endpointStrategy.release();
1107 
1108 			for( WsdlTestSuite testSuite : testSuites )
1109 				testSuite.release();
1110 
1111 			for( WsdlMockService mockService : mockServices )
1112 				mockService.release();
1113 
1114 			for( AbstractInterface<?> iface : interfaces )
1115 				iface.release();
1116 
1117 			if( wssContainer != null )
1118 			{
1119 				wssContainer.release();
1120 				wssContainer = null;
1121 			}
1122 		}
1123 
1124 		projectListeners.clear();
1125 
1126 		if( afterLoadScriptEngine != null )
1127 			afterLoadScriptEngine.release();
1128 
1129 		if( beforeSaveScriptEngine != null )
1130 			beforeSaveScriptEngine.release();
1131 	}
1132 
1133 	public WsdlMockService addNewMockService( String name )
1134 	{
1135 		WsdlMockService mockService = new WsdlMockService( this, getConfig().addNewMockService() );
1136 		mockService.setName( name );
1137 		mockServices.add( mockService );
1138 		fireMockServiceAdded( mockService );
1139 
1140 		return mockService;
1141 	}
1142 
1143 	public WsdlMockService getMockServiceAt( int index )
1144 	{
1145 		return mockServices.get( index );
1146 	}
1147 
1148 	public WsdlMockService getMockServiceByName( String mockServiceName )
1149 	{
1150 		return ( WsdlMockService )getWsdlModelItemByName( mockServices, mockServiceName );
1151 	}
1152 
1153 	public int getMockServiceCount()
1154 	{
1155 		return mockServices.size();
1156 	}
1157 
1158 	public void removeMockService( WsdlMockService mockService )
1159 	{
1160 		int ix = mockServices.indexOf( mockService );
1161 		mockServices.remove( ix );
1162 
1163 		try
1164 		{
1165 			fireMockServiceRemoved( mockService );
1166 		}
1167 		finally
1168 		{
1169 			mockService.release();
1170 			getConfig().removeMockService( ix );
1171 		}
1172 	}
1173 
1174 	public List<TestSuite> getTestSuiteList()
1175 	{
1176 		return new ArrayList<TestSuite>( testSuites );
1177 	}
1178 
1179 	public List<MockService> getMockServiceList()
1180 	{
1181 		return new ArrayList<MockService>( mockServices );
1182 	}
1183 
1184 	public List<Interface> getInterfaceList()
1185 	{
1186 		return new ArrayList<Interface>( interfaces );
1187 	}
1188 
1189 	public Map<String, Interface> getInterfaces()
1190 	{
1191 		Map<String, Interface> result = new HashMap<String, Interface>();
1192 		for( Interface iface : interfaces )
1193 			result.put( iface.getName(), iface );
1194 
1195 		return result;
1196 	}
1197 
1198 	public Map<String, TestSuite> getTestSuites()
1199 	{
1200 		Map<String, TestSuite> result = new HashMap<String, TestSuite>();
1201 		for( TestSuite iface : testSuites )
1202 			result.put( iface.getName(), iface );
1203 
1204 		return result;
1205 	}
1206 
1207 	public Map<String, MockService> getMockServices()
1208 	{
1209 		Map<String, MockService> result = new HashMap<String, MockService>();
1210 		for( MockService mockService : mockServices )
1211 			result.put( mockService.getName(), mockService );
1212 
1213 		return result;
1214 	}
1215 
1216 	public void reload() throws SoapUIException
1217 	{
1218 		reload( path );
1219 	}
1220 
1221 	public void reload( String path ) throws SoapUIException
1222 	{
1223 		this.path = path;
1224 		getWorkspace().reloadProject( this );
1225 	}
1226 
1227 	public boolean hasNature( String natureId )
1228 	{
1229 		Settings projectSettings = getSettings();
1230 		String projectNature = projectSettings.getString( ProjectSettings.PROJECT_NATURE, null );
1231 		return natureId.equals( projectNature );
1232 	}
1233 
1234 	public AbstractInterface<?> importInterface( AbstractInterface<?> iface, boolean importEndpoints, boolean createCopy )
1235 	{
1236 		iface.beforeSave();
1237 
1238 		InterfaceConfig ifaceConfig = ( InterfaceConfig )iface.getConfig().copy();
1239 		ifaceConfig = ( InterfaceConfig )getConfig().addNewInterface().set( ifaceConfig );
1240 
1241 		AbstractInterface<?> imported = InterfaceFactoryRegistry.build( this, ifaceConfig );
1242 		interfaces.add( imported );
1243 
1244 		if( iface.getProject() != this && importEndpoints )
1245 		{
1246 			endpointStrategy.importEndpoints( iface );
1247 		}
1248 
1249 		if( createCopy )
1250 			ModelSupport.unsetIds( imported );
1251 
1252 		imported.afterLoad();
1253 		fireInterfaceAdded( imported );
1254 
1255 		return imported;
1256 	}
1257 
1258 	public WsdlTestSuite importTestSuite( WsdlTestSuite testSuite, String name, int index, boolean createCopy,
1259 			String description )
1260 	{
1261 		testSuite.beforeSave();
1262 		TestSuiteConfig testSuiteConfig = index == -1 ? ( TestSuiteConfig )getConfig().addNewTestSuite().set(
1263 				testSuite.getConfig().copy() ) : ( TestSuiteConfig )getConfig().insertNewTestSuite( index ).set(
1264 				testSuite.getConfig().copy() );
1265 
1266 		testSuiteConfig.setName( name );
1267 
1268 		testSuite = buildTestSuite( testSuiteConfig );
1269 		if( description != null )
1270 			testSuite.setDescription( description );
1271 
1272 		if( index == -1 )
1273 			testSuites.add( testSuite );
1274 		else
1275 			testSuites.add( index, testSuite );
1276 
1277 		if( createCopy )
1278 			ModelSupport.unsetIds( testSuite );
1279 
1280 		testSuite.afterLoad();
1281 		fireTestSuiteAdded( testSuite );
1282 
1283 		resolveImportedTestSuite( testSuite );
1284 
1285 		return testSuite;
1286 	}
1287 
1288 	public WsdlMockService importMockService( WsdlMockService mockService, String name, boolean createCopy,
1289 			String description )
1290 	{
1291 		mockService.beforeSave();
1292 		MockServiceConfig mockServiceConfig = ( MockServiceConfig )getConfig().addNewMockService().set(
1293 				mockService.getConfig().copy() );
1294 		mockServiceConfig.setName( name );
1295 		if( mockServiceConfig.isSetId() && createCopy )
1296 			mockServiceConfig.unsetId();
1297 		mockService = new WsdlMockService( this, mockServiceConfig );
1298 		mockService.setDescription( description );
1299 		mockServices.add( mockService );
1300 		if( createCopy )
1301 			ModelSupport.unsetIds( mockService );
1302 
1303 		mockService.afterLoad();
1304 
1305 		fireMockServiceAdded( mockService );
1306 
1307 		return mockService;
1308 	}
1309 
1310 	public EndpointStrategy getEndpointStrategy()
1311 	{
1312 		return endpointStrategy;
1313 	}
1314 
1315 	public boolean isOpen()
1316 	{
1317 		return open;
1318 	}
1319 
1320 	public List<? extends ModelItem> getChildren()
1321 	{
1322 		ArrayList<ModelItem> list = new ArrayList<ModelItem>();
1323 		list.addAll( getInterfaceList() );
1324 		list.addAll( getTestSuiteList() );
1325 		list.addAll( getMockServiceList() );
1326 		return list;
1327 	}
1328 
1329 	public void setAfterLoadScript( String script )
1330 	{
1331 		String oldScript = getAfterLoadScript();
1332 
1333 		if( !getConfig().isSetAfterLoadScript() )
1334 			getConfig().addNewAfterLoadScript();
1335 
1336 		getConfig().getAfterLoadScript().setStringValue( script );
1337 		if( afterLoadScriptEngine != null )
1338 			afterLoadScriptEngine.setScript( script );
1339 
1340 		notifyPropertyChanged( AFTER_LOAD_SCRIPT_PROPERTY, oldScript, script );
1341 	}
1342 
1343 	public String getAfterLoadScript()
1344 	{
1345 		return getConfig().isSetAfterLoadScript() ? getConfig().getAfterLoadScript().getStringValue() : null;
1346 	}
1347 
1348 	public void setBeforeSaveScript( String script )
1349 	{
1350 		String oldScript = getBeforeSaveScript();
1351 
1352 		if( !getConfig().isSetBeforeSaveScript() )
1353 			getConfig().addNewBeforeSaveScript();
1354 
1355 		getConfig().getBeforeSaveScript().setStringValue( script );
1356 		if( beforeSaveScriptEngine != null )
1357 			beforeSaveScriptEngine.setScript( script );
1358 
1359 		notifyPropertyChanged( BEFORE_SAVE_SCRIPT_PROPERTY, oldScript, script );
1360 	}
1361 
1362 	public String getBeforeSaveScript()
1363 	{
1364 		return getConfig().isSetBeforeSaveScript() ? getConfig().getBeforeSaveScript().getStringValue() : null;
1365 	}
1366 
1367 	public Object runAfterLoadScript() throws Exception
1368 	{
1369 		String script = getAfterLoadScript();
1370 		if( StringUtils.isNullOrEmpty( script ) )
1371 			return null;
1372 
1373 		if( afterLoadScriptEngine == null )
1374 		{
1375 			afterLoadScriptEngine = SoapUIScriptEngineRegistry.create( this );
1376 			afterLoadScriptEngine.setScript( script );
1377 		}
1378 
1379 		afterLoadScriptEngine.setVariable( "context", context );
1380 		afterLoadScriptEngine.setVariable( "project", this );
1381 		afterLoadScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
1382 		return afterLoadScriptEngine.run();
1383 	}
1384 
1385 	public Object runBeforeSaveScript() throws Exception
1386 	{
1387 		String script = getBeforeSaveScript();
1388 		if( StringUtils.isNullOrEmpty( script ) )
1389 			return null;
1390 
1391 		if( beforeSaveScriptEngine == null )
1392 		{
1393 			beforeSaveScriptEngine = SoapUIScriptEngineRegistry.create( this );
1394 			beforeSaveScriptEngine.setScript( script );
1395 		}
1396 
1397 		beforeSaveScriptEngine.setVariable( "context", context );
1398 		beforeSaveScriptEngine.setVariable( "project", this );
1399 		beforeSaveScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
1400 		return beforeSaveScriptEngine.run();
1401 	}
1402 
1403 	public PropertyExpansionContext getContext()
1404 	{
1405 		return context;
1406 	}
1407 
1408 	public DefaultWssContainer getWssContainer()
1409 	{
1410 		return wssContainer;
1411 	}
1412 
1413 	@Override
1414 	public void resolve( ResolveContext<?> context )
1415 	{
1416 		super.resolve( context );
1417 
1418 		wssContainer.resolve( context );
1419 	}
1420 
1421 	public PropertyExpansion[] getPropertyExpansions()
1422 	{
1423 		List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
1424 
1425 		result.addAll( Arrays.asList( wssContainer.getPropertyExpansions() ) );
1426 		// result.addAll(Arrays.asList(databaseConnectionContainer.
1427 		// getPropertyExpansions()));
1428 
1429 		return result.toArray( new PropertyExpansion[result.size()] );
1430 
1431 	}
1432 
1433 	public String getPropertiesLabel()
1434 	{
1435 		return "Custom Properties";
1436 	}
1437 
1438 	public String getShadowPassword()
1439 	{
1440 		projectPassword = getSettings() == null ? projectPassword : getSettings().getString(
1441 				ProjectSettings.SHADOW_PASSWORD, null );
1442 		return projectPassword;
1443 	}
1444 
1445 	public void setShadowPassword( String password )
1446 	{
1447 		String oldPassword = getSettings().getString( ProjectSettings.SHADOW_PASSWORD, null );
1448 		getSettings().setString( ProjectSettings.SHADOW_PASSWORD, password );
1449 		notifyPropertyChanged( "projectPassword", oldPassword, password );
1450 	}
1451 
1452 	public String getHermesConfig()
1453 	{
1454 		hermesConfig = getSettings() == null ? hermesConfig : resolveHermesConfig();
1455 		return hermesConfig;
1456 	}
1457 
1458 	private String resolveHermesConfig()
1459 	{
1460 		String hermesConfigProperty = getSettings().getString( ProjectSettings.HERMES_CONFIG, null );
1461 		if( hermesConfigProperty != null && !hermesConfigProperty.equals( "" ) )
1462 		{
1463 			return hermesConfigProperty;
1464 		}
1465 		else if( System.getenv( "HERMES_CONFIG" ) != null )
1466 		{
1467 			return System.getenv( "HERMES_CONFIG" );
1468 		}
1469 		else
1470 		{
1471 			return "${#System#user.home}//.hermes";
1472 		}
1473 
1474 	}
1475 
1476 	public void setHermesConfig( String hermesConfigPath )
1477 	{
1478 		String oldHermesConfigPath = getSettings().getString( ProjectSettings.HERMES_CONFIG, null );
1479 		getSettings().setString( ProjectSettings.HERMES_CONFIG, hermesConfigPath );
1480 		notifyPropertyChanged( "hermesConfig", oldHermesConfigPath, hermesConfigPath );
1481 
1482 	}
1483 
1484 	public void inspect()
1485 	{
1486 
1487 		if( !isOpen() )
1488 			return;
1489 
1490 		byte data[] = projectDocument.getSoapuiProject().getEncryptedContent();
1491 		if( data != null && data.length > 0 )
1492 		{
1493 			try
1494 			{
1495 				reload();
1496 			}
1497 			catch( SoapUIException e )
1498 			{
1499 				e.printStackTrace();
1500 			}
1501 		}
1502 	}
1503 
1504 	public int getEncrypted()
1505 	{
1506 		return this.encrypted;
1507 	}
1508 
1509 	public int setEncrypted( int code )
1510 	{
1511 		return this.encrypted = code;
1512 	}
1513 
1514 	public void propertyChange( PropertyChangeEvent evt )
1515 	{
1516 		if( "projectPassword".equals( evt.getPropertyName() ) )
1517 		{
1518 			if( encrypted == 0 & ( evt.getOldValue() == null || ( ( String )evt.getOldValue() ).length() == 0 ) )
1519 			{
1520 				encrypted = 1;
1521 			}
1522 			if( encrypted == 1 & ( evt.getNewValue() == null || ( ( String )evt.getNewValue() ).length() == 0 ) )
1523 			{
1524 				encrypted = 0;
1525 			}
1526 
1527 			if( SoapUI.getNavigator() != null )
1528 				SoapUI.getNavigator().repaint();
1529 		}
1530 	}
1531 
1532 	public SoapuiProjectDocumentConfig getProjectDocument()
1533 	{
1534 		return projectDocument;
1535 	}
1536 
1537 	public int getInterfaceCount( String type )
1538 	{
1539 		int result = 0;
1540 
1541 		for( AbstractInterface<?> iface : interfaces )
1542 		{
1543 			if( iface.getType().equals( type ) )
1544 				result++ ;
1545 		}
1546 
1547 		return result;
1548 	}
1549 
1550 	public List<AbstractInterface<?>> getInterfaces( String type )
1551 	{
1552 		ArrayList<AbstractInterface<?>> result = new ArrayList<AbstractInterface<?>>();
1553 
1554 		for( AbstractInterface<?> iface : interfaces )
1555 		{
1556 			if( iface.getType().equals( type ) )
1557 				result.add( iface );
1558 		}
1559 
1560 		return result;
1561 	}
1562 
1563 	public void importTestSuite( File file )
1564 	{
1565 		if( !file.exists() )
1566 		{
1567 			UISupport.showErrorMessage( "Error loading test case " );
1568 			return;
1569 		}
1570 
1571 		TestSuiteDocumentConfig newTestSuiteConfig = null;
1572 
1573 		try
1574 		{
1575 			newTestSuiteConfig = TestSuiteDocumentConfig.Factory.parse( file );
1576 		}
1577 		catch( Exception e )
1578 		{
1579 			SoapUI.logError( e );
1580 		}
1581 
1582 		if( newTestSuiteConfig == null )
1583 		{
1584 			UISupport.showErrorMessage( "Not valild test case xml" );
1585 		}
1586 		else
1587 		{
1588 			TestSuiteConfig config = ( TestSuiteConfig )projectDocument.getSoapuiProject().addNewTestSuite().set(
1589 					newTestSuiteConfig.getTestSuite() );
1590 			WsdlTestSuite testSuite = buildTestSuite( config );
1591 
1592 			ModelSupport.unsetIds( testSuite );
1593 			testSuite.afterLoad();
1594 
1595 			testSuites.add( testSuite );
1596 			fireTestSuiteAdded( testSuite );
1597 
1598 			resolveImportedTestSuite( testSuite );
1599 		}
1600 	}
1601 
1602 	private void resolveImportedTestSuite( WsdlTestSuite testSuite )
1603 	{
1604 		ResolveDialog resolver = new ResolveDialog( "Validate TestSuite", "Checks TestSuite for inconsistencies", null );
1605 		resolver.setShowOkMessage( false );
1606 		resolver.resolve( testSuite );
1607 	}
1608 
1609 	/***
1610 	 * @see com.eviware.soapui.impl.WsdlInterfaceFactory.importWsdl
1611 	 * @deprecated
1612 	 */
1613 
1614 	public WsdlInterface[] importWsdl( String url, boolean createRequests ) throws SoapUIException
1615 	{
1616 		return WsdlInterfaceFactory.importWsdl( this, url, createRequests );
1617 	}
1618 
1619 	/***
1620 	 * @see com.eviware.soapui.impl.WsdlInterfaceFactory.importWsdl
1621 	 * @deprecated see WsdlInterfaceFactory
1622 	 */
1623 
1624 	public WsdlInterface[] importWsdl( String url, boolean createRequests, WsdlLoader wsdlLoader )
1625 			throws SoapUIException
1626 	{
1627 		return WsdlInterfaceFactory.importWsdl( this, url, createRequests, null, wsdlLoader );
1628 	}
1629 
1630 	/***
1631 	 * @see com.eviware.soapui.impl.WsdlInterfaceFactory.importWsdl
1632 	 * @deprecated see WsdlInterfaceFactory
1633 	 */
1634 
1635 	public WsdlInterface[] importWsdl( String url, boolean createRequests, QName bindingName, WsdlLoader wsdlLoader )
1636 			throws SoapUIException
1637 	{
1638 		return WsdlInterfaceFactory.importWsdl( this, url, createRequests, bindingName, wsdlLoader );
1639 	}
1640 
1641 	public void setDefaultScriptLanguage( String id )
1642 	{
1643 		getConfig().setDefaultScriptLanguage( id );
1644 	}
1645 
1646 	public String getDefaultScriptLanguage()
1647 	{
1648 		if( getConfig().isSetDefaultScriptLanguage() )
1649 			return getConfig().getDefaultScriptLanguage();
1650 		else
1651 			return SoapUIScriptEngineRegistry.DEFAULT_SCRIPT_ENGINE_ID;
1652 	}
1653 
1654 	public int getIndexOfTestSuite( TestSuite testSuite )
1655 	{
1656 		return testSuites.indexOf( testSuite );
1657 	}
1658 
1659 	public String getBeforeRunScript()
1660 	{
1661 		return getConfig().isSetBeforeRunScript() ? getConfig().getBeforeRunScript().getStringValue() : null;
1662 	}
1663 
1664 	public void setBeforeRunScript( String script )
1665 	{
1666 		String oldScript = getBeforeRunScript();
1667 
1668 		if( !getConfig().isSetBeforeRunScript() )
1669 			getConfig().addNewBeforeRunScript();
1670 
1671 		getConfig().getBeforeRunScript().setStringValue( script );
1672 		if( beforeRunScriptEngine != null )
1673 			beforeRunScriptEngine.setScript( script );
1674 
1675 		notifyPropertyChanged( "beforeRunScript", oldScript, script );
1676 	}
1677 
1678 	public Object runBeforeRunScript( ProjectRunContext context, ProjectRunner runner ) throws Exception
1679 	{
1680 		String script = getBeforeRunScript();
1681 		if( StringUtils.isNullOrEmpty( script ) )
1682 			return null;
1683 
1684 		if( beforeRunScriptEngine == null )
1685 		{
1686 			beforeRunScriptEngine = SoapUIScriptEngineRegistry.create( this );
1687 			beforeRunScriptEngine.setScript( script );
1688 		}
1689 
1690 		beforeRunScriptEngine.setVariable( "runner", runner );
1691 		beforeRunScriptEngine.setVariable( "context", context );
1692 		beforeRunScriptEngine.setVariable( "project", this );
1693 		beforeRunScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
1694 		return beforeRunScriptEngine.run();
1695 	}
1696 
1697 	public String getAfterRunScript()
1698 	{
1699 		return getConfig().isSetAfterRunScript() ? getConfig().getAfterRunScript().getStringValue() : null;
1700 	}
1701 
1702 	public void setAfterRunScript( String script )
1703 	{
1704 		String oldScript = getAfterRunScript();
1705 
1706 		if( !getConfig().isSetAfterRunScript() )
1707 			getConfig().addNewAfterRunScript();
1708 
1709 		getConfig().getAfterRunScript().setStringValue( script );
1710 		if( afterRunScriptEngine != null )
1711 			afterRunScriptEngine.setScript( script );
1712 
1713 		notifyPropertyChanged( "afterRunScript", oldScript, script );
1714 	}
1715 
1716 	public Object runAfterRunScript( ProjectRunContext context, ProjectRunner runner ) throws Exception
1717 	{
1718 		String script = getAfterRunScript();
1719 		if( StringUtils.isNullOrEmpty( script ) )
1720 			return null;
1721 
1722 		if( afterRunScriptEngine == null )
1723 		{
1724 			afterRunScriptEngine = SoapUIScriptEngineRegistry.create( this );
1725 			afterRunScriptEngine.setScript( script );
1726 		}
1727 
1728 		afterRunScriptEngine.setVariable( "runner", runner );
1729 		afterRunScriptEngine.setVariable( "context", context );
1730 		afterRunScriptEngine.setVariable( "project", this );
1731 		afterRunScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
1732 		return afterRunScriptEngine.run();
1733 	}
1734 
1735 	public void addProjectRunListener( ProjectRunListener projectRunListener )
1736 	{
1737 		runListeners.add( projectRunListener );
1738 	}
1739 
1740 	public void removeProjectRunListener( ProjectRunListener projectRunListener )
1741 	{
1742 		runListeners.remove( projectRunListener );
1743 	}
1744 
1745 	public WsdlProjectRunner run( StringToObjectMap context, boolean async )
1746 	{
1747 		WsdlProjectRunner runner = new WsdlProjectRunner( this, context );
1748 		runner.start( async );
1749 		return runner;
1750 	}
1751 
1752 	public boolean isAbortOnError()
1753 	{
1754 		return getConfig().getAbortOnError();
1755 	}
1756 
1757 	// public boolean isFailOnErrors()
1758 	// {
1759 	// return getConfig().getFailOnErrors();
1760 	// }
1761 	//	
1762 	// public void setFailOnErrors( boolean arg0 )
1763 	// {
1764 	// getConfig().setFailOnErrors( arg0 );
1765 	// }
1766 
1767 	public void setAbortOnError( boolean arg0 )
1768 	{
1769 		getConfig().setAbortOnError( arg0 );
1770 	}
1771 
1772 	public long getTimeout()
1773 	{
1774 		return getConfig().getTimeout();
1775 	}
1776 
1777 	public void setTimeout( long timeout )
1778 	{
1779 		getConfig().setTimeout( timeout );
1780 	}
1781 
1782 	public ProjectRunListener[] getProjectRunListeners()
1783 	{
1784 		return runListeners.toArray( new ProjectRunListener[runListeners.size()] );
1785 	}
1786 
1787 	public TestSuiteRunType getRunType()
1788 	{
1789 		Enum runType = getConfig().getRunType();
1790 
1791 		if( TestSuiteRunTypesConfig.PARALLELL.equals( runType ) )
1792 			return TestSuiteRunType.PARALLEL;
1793 		else
1794 			return TestSuiteRunType.SEQUENTIAL;
1795 	}
1796 
1797 	public void setRunType( TestSuiteRunType runType )
1798 	{
1799 		TestSuiteRunType oldRunType = getRunType();
1800 
1801 		if( runType == TestSuiteRunType.PARALLEL && oldRunType != TestSuiteRunType.PARALLEL )
1802 		{
1803 			getConfig().setRunType( TestSuiteRunTypesConfig.PARALLELL );
1804 			notifyPropertyChanged( "runType", oldRunType, runType );
1805 		}
1806 		else if( runType == TestSuiteRunType.SEQUENTIAL && oldRunType != TestSuiteRunType.SEQUENTIAL )
1807 		{
1808 			getConfig().setRunType( TestSuiteRunTypesConfig.SEQUENTIAL );
1809 			notifyPropertyChanged( "runType", oldRunType, runType );
1810 		}
1811 	}
1812 
1813 	public WsdlTestSuite moveTestSuite( int ix, int offset )
1814 	{
1815 		WsdlTestSuite testSuite = testSuites.get( ix );
1816 
1817 		if( offset == 0 )
1818 			return testSuite;
1819 
1820 		testSuites.remove( ix );
1821 		testSuites.add( ix + offset, testSuite );
1822 
1823 		TestSuiteConfig[] configs = new TestSuiteConfig[testSuites.size()];
1824 
1825 		for( int c = 0; c < testSuites.size(); c++ )
1826 		{
1827 			if( offset > 0 )
1828 			{
1829 				if( c < ix )
1830 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c ).copy();
1831 				else if( c < ( ix + offset ) )
1832 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c + 1 ).copy();
1833 				else if( c == ix + offset )
1834 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( ix ).copy();
1835 				else
1836 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c ).copy();
1837 			}
1838 			else
1839 			{
1840 				if( c < ix + offset )
1841 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c ).copy();
1842 				else if( c == ix + offset )
1843 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( ix ).copy();
1844 				else if( c <= ix )
1845 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c - 1 ).copy();
1846 				else
1847 					configs[c] = ( TestSuiteConfig )getConfig().getTestSuiteArray( c ).copy();
1848 			}
1849 		}
1850 
1851 		getConfig().setTestSuiteArray( configs );
1852 		for( int c = 0; c < configs.length; c++ )
1853 		{
1854 			testSuites.get( c ).resetConfigOnMove( getConfig().getTestSuiteArray( c ) );
1855 		}
1856 
1857 		fireTestSuiteMoved( testSuite, ix, offset );
1858 		return testSuite;
1859 
1860 	}
1861 
1862 	public void importMockService( File file )
1863 	{
1864 		if( !file.exists() )
1865 		{
1866 			UISupport.showErrorMessage( "Error loading test case " );
1867 			return;
1868 		}
1869 
1870 		MockServiceDocumentConfig newMockServiceConfig = null;
1871 
1872 		try
1873 		{
1874 			newMockServiceConfig = MockServiceDocumentConfig.Factory.parse( file );
1875 		}
1876 		catch( Exception e )
1877 		{
1878 			SoapUI.logError( e );
1879 		}
1880 
1881 		if( newMockServiceConfig == null )
1882 		{
1883 			UISupport.showErrorMessage( "Not valid mock service xml" );
1884 		}
1885 		else
1886 		{
1887 			MockServiceConfig config = ( MockServiceConfig )projectDocument.getSoapuiProject().addNewMockService().set(
1888 					newMockServiceConfig.getMockService() );
1889 			WsdlMockService mockService = new WsdlMockService( this, config );
1890 
1891 			ModelSupport.unsetIds( mockService );
1892 			mockService.afterLoad();
1893 
1894 			mockServices.add( mockService );
1895 			fireMockServiceAdded( mockService );
1896 
1897 			resolveImportedMockService( mockService );
1898 		}
1899 	}
1900 
1901 	private void resolveImportedMockService( WsdlMockService mockService )
1902 	{
1903 		ResolveDialog resolver = new ResolveDialog( "Validate MockService", "Checks MockService for inconsistencies",
1904 				null );
1905 		resolver.setShowOkMessage( false );
1906 		resolver.resolve( mockService );
1907 	}
1908 }