View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.config.*;
17  import com.eviware.soapui.impl.WorkspaceImpl;
18  import com.eviware.soapui.impl.support.AbstractInterface;
19  import com.eviware.soapui.impl.wsdl.endpoint.DefaultEndpointStrategy;
20  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
21  import com.eviware.soapui.impl.wsdl.support.wsdl.UrlWsdlLoader;
22  import com.eviware.soapui.impl.wsdl.support.wss.DefaultWssContainer;
23  import com.eviware.soapui.model.ModelItem;
24  import com.eviware.soapui.model.iface.Interface;
25  import com.eviware.soapui.model.mock.MockService;
26  import com.eviware.soapui.model.project.EndpointStrategy;
27  import com.eviware.soapui.model.project.Project;
28  import com.eviware.soapui.model.project.ProjectListener;
29  import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
30  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
31  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
32  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
33  import com.eviware.soapui.model.settings.Settings;
34  import com.eviware.soapui.model.testsuite.TestSuite;
35  import com.eviware.soapui.settings.ProjectSettings;
36  import com.eviware.soapui.settings.UISettings;
37  import com.eviware.soapui.settings.WsdlSettings;
38  import com.eviware.soapui.support.SoapUIException;
39  import com.eviware.soapui.support.StringUtils;
40  import com.eviware.soapui.support.Tools;
41  import com.eviware.soapui.support.UISupport;
42  import com.eviware.soapui.support.resolver.ResolveContext;
43  import com.eviware.soapui.support.resolver.ResolveDialog;
44  import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
45  import com.eviware.soapui.support.scripting.SoapUIScriptEngineRegistry;
46  import org.apache.commons.ssl.OpenSSL;
47  import org.apache.log4j.Logger;
48  import org.apache.xmlbeans.XmlError;
49  import org.apache.xmlbeans.XmlException;
50  import org.apache.xmlbeans.XmlObject;
51  import org.apache.xmlbeans.XmlOptions;
52  
53  import javax.swing.*;
54  import java.beans.PropertyChangeEvent;
55  import java.beans.PropertyChangeListener;
56  import java.beans.PropertyChangeSupport;
57  import java.io.ByteArrayOutputStream;
58  import java.io.File;
59  import java.io.FileOutputStream;
60  import java.io.IOException;
61  import java.net.MalformedURLException;
62  import java.net.URL;
63  import java.security.GeneralSecurityException;
64  import java.util.*;
65  
66  /***
67   * WSDL project implementation
68   * 
69   * @author Ole.Matzura
70   */
71  
72  public class WsdlProject extends AbstractTestPropertyHolderWsdlModelItem<ProjectConfig> implements Project,
73  		PropertyExpansionContainer, PropertyChangeListener
74  {
75  	public final static String AFTER_LOAD_SCRIPT_PROPERTY = WsdlProject.class.getName() + "@setupScript";
76  	public final static String BEFORE_SAVE_SCRIPT_PROPERTY = WsdlProject.class.getName() + "@tearDownScript";
77  	public final static String RESOURCE_ROOT_PROPERTY = WsdlProject.class.getName() + "@resourceRoot";
78  
79  	private WorkspaceImpl workspace;
80  	protected String path;
81  	protected List<AbstractInterface<?>> interfaces = new ArrayList<AbstractInterface<?>>();
82  	protected List<WsdlTestSuite> testSuites = new ArrayList<WsdlTestSuite>();
83  	protected List<WsdlMockService> mockServices = new ArrayList<WsdlMockService>();
84  	private Set<ProjectListener> projectListeners = new HashSet<ProjectListener>();
85  	protected SoapuiProjectDocumentConfig projectDocument;
86  	private ImageIcon disabledIcon;
87  	private ImageIcon closedIcon;
88  	private ImageIcon remoteIcon;
89  	private ImageIcon openEncyptedIcon;
90  	protected EndpointStrategy endpointStrategy = new DefaultEndpointStrategy();
91  	protected long lastModified;
92  	private boolean remote;
93  	private boolean open = true;
94  	private boolean disabled;
95  
96  	private SoapUIScriptEngine afterLoadScriptEngine;
97  	private SoapUIScriptEngine beforeSaveScriptEngine;
98  	private PropertyExpansionContext context = new DefaultPropertyExpansionContext(this);
99  	protected DefaultWssContainer wssContainer;
100 	private String projectPassword = null;
101 	/*
102 	 * 3 state flag: 1. 0 - project not encrypted 2. 1 - encrypted , good
103 	 * password, means that it could be successfully decrypted 3. -1 - encrypted,
104 	 * but with bad password or no password.
105 	 */
106 	protected int encrypted;
107 	private ImageIcon closedEncyptedIcon;
108 	private final PropertyChangeSupport pcs;
109 
110 	protected final static Logger log = Logger.getLogger(WsdlProject.class);
111 
112 	public WsdlProject() throws XmlException, IOException, SoapUIException
113 	{
114 		this((WorkspaceImpl) null);
115 	}
116 
117 	public WsdlProject(String path) throws XmlException, IOException, SoapUIException
118 	{
119 		this(path, (WorkspaceImpl) null);
120 	}
121 
122 	public WsdlProject(String projectFile, String projectPassword)
123 	{
124 		this(projectFile, null, true, true, null, projectPassword);
125 	}
126 
127 	public WsdlProject(WorkspaceImpl workspace)
128 	{
129 		this(null, workspace, true);
130 	}
131 
132 	public WsdlProject(String path, WorkspaceImpl workspace)
133 	{
134 		this(path, workspace, true);
135 	}
136 
137 	public WsdlProject(String path, WorkspaceImpl workspace, boolean create)
138 	{
139 		this(path, workspace, create, true, null, null);
140 	}
141 
142 	public WsdlProject(String path, WorkspaceImpl workspace, boolean create, boolean open, String tempName,
143 			String projectPassword)
144 	{
145 		super(null, workspace, "/project.gif");
146 
147 		pcs = new PropertyChangeSupport(this);
148 
149 		this.workspace = workspace;
150 		this.path = path;
151 		this.projectPassword = projectPassword;
152 
153 		try
154 		{
155 			if (path != null && open)
156 			{
157 				File file = new File(path);
158 				if (file.exists())
159 				{
160 					try
161 					{
162 						loadProject(file.toURI().toURL());
163 						lastModified = file.lastModified();
164 					}
165 					catch (MalformedURLException e)
166 					{
167 						SoapUI.logError(e);
168 						disabled = true;
169 					}
170 				}
171 				else
172 				{
173 					try
174 					{
175 						remote = true;
176 						loadProject(new URL(path));
177 					}
178 					catch (MalformedURLException e)
179 					{
180 						SoapUI.logError(e);
181 						disabled = true;
182 					}
183 				}
184 			}
185 		}
186 		catch (SoapUIException e)
187 		{
188 			SoapUI.logError(e);
189 			disabled = true;
190 		}
191 		finally
192 		{
193 			closedIcon = UISupport.createImageIcon("/closedProject.gif");
194 			remoteIcon = UISupport.createImageIcon("/remoteProject.gif");
195 			disabledIcon = UISupport.createImageIcon("/disabledProject.gif");
196 			openEncyptedIcon = UISupport.createImageIcon("/openEncryptedProject.gif");
197 			closedEncyptedIcon = UISupport.createImageIcon("/closedEncryptedProject.gif");
198 
199 			this.open = open && !disabled && (this.encrypted != -1);
200 
201 			if (projectDocument == null)
202 			{
203 				projectDocument = SoapuiProjectDocumentConfig.Factory.newInstance();
204 				setConfig(projectDocument.addNewSoapuiProject());
205 				if (tempName != null || path != null)
206 					getConfig().setName(StringUtils.isNullOrEmpty(tempName) ? getNameFromPath() : tempName);
207 
208 				setPropertiesConfig(getConfig().addNewProperties());
209 				wssContainer = new DefaultWssContainer(this, getConfig().addNewWssContainer());
210 				// setResourceRoot("${projectDir}");
211 			}
212 
213 			if (getConfig() != null)
214 			{
215 				endpointStrategy.init(this);
216 			}
217 			if (getSettings() != null)
218 			{
219 				setProjectRoot(path);
220 			}
221 
222 			for (ProjectListener listener : SoapUI.getListenerRegistry().getListeners(ProjectListener.class))
223 			{
224 				addProjectListener(listener);
225 			}
226 
227 			addPropertyChangeListener(this);
228 
229 		}
230 	}
231 
232    protected PropertyChangeSupport getPropertyChangeSupport()
233    {
234       return pcs;
235    }
236 
237 	public boolean isRemote()
238 	{
239 		return remote;
240 	}
241 
242 	public void loadProject(URL file) throws SoapUIException
243 	{
244 		try
245 		{
246 			UISupport.setHourglassCursor();
247 
248 			UrlWsdlLoader loader = new UrlWsdlLoader(file.toString(), this);
249 			loader.setUseWorker(false);
250 			projectDocument = SoapuiProjectDocumentConfig.Factory.parse(loader.load());
251 
252 			// see if there is encoded data
253 			this.encrypted = checkForEncodedData(projectDocument.getSoapuiProject());
254 
255 			setConfig(projectDocument.getSoapuiProject());
256 
257 			// removed cached definitions if caching is disabled
258 			if (!getSettings().getBoolean(WsdlSettings.CACHE_WSDLS))
259 			{
260 				removeDefinitionCaches(projectDocument);
261 			}
262 
263 			log.info("Loaded project from [" + file.toString() + "]");
264 
265 			List<InterfaceConfig> interfaceConfigs = getConfig().getInterfaceList();
266 			for (InterfaceConfig config : interfaceConfigs)
267 			{
268 				AbstractInterface<?> iface = InterfaceFactoryRegistry.build(this, config);
269 				interfaces.add(iface);
270 			}
271 
272 			List<TestSuiteConfig> testSuiteConfigs = getConfig().getTestSuiteList();
273 			for (TestSuiteConfig config : testSuiteConfigs)
274 			{
275 				testSuites.add(new WsdlTestSuite(this, config));
276 			}
277 
278 			List<MockServiceConfig> mockServiceConfigs = getConfig().getMockServiceList();
279 			for (MockServiceConfig config : mockServiceConfigs)
280 			{
281 				mockServices.add(new WsdlMockService(this, config));
282 			}
283 
284 			if (!getConfig().isSetWssContainer())
285 				getConfig().addNewWssContainer();
286 
287 			wssContainer = new DefaultWssContainer(this, getConfig().getWssContainer());
288 
289 			endpointStrategy.init(this);
290 
291 			if (!getConfig().isSetProperties())
292 				getConfig().addNewProperties();
293 
294 			setPropertiesConfig(getConfig().getProperties());
295 			afterLoad();
296 		}
297 		catch (Exception e)
298 		{
299 			if (e instanceof XmlException)
300 			{
301 				XmlException xe = (XmlException) e;
302 				XmlError error = xe.getError();
303 				if (error != null)
304 					System.err.println("Error at line " + error.getLine() + ", column " + error.getColumn());
305 			}
306 
307 			e.printStackTrace();
308 			throw new SoapUIException("Failed to load project from file [" + file.toString() + "]", e);
309 		}
310 		finally
311 		{
312 			UISupport.resetCursor();
313 		}
314 	}
315 
316 	/***
317 	 * Decode encrypted data and restore user/pass
318 	 * 
319 	 * @param soapuiProject
320 	 * @return 0 - not encrypted, 1 - successfull decryption , -1 error while
321 	 *         decrypting, bad password, no password.
322 	 * @throws IOException
323 	 * @throws GeneralSecurityException
324 	 * @author robert nemet
325 	 */
326 	protected int checkForEncodedData(ProjectConfig soapuiProject) throws IOException, GeneralSecurityException
327 	{
328 
329 		byte[] encryptedContent = soapuiProject.getEncryptedContent();
330 		char[] password = null;
331 
332 		// no encrypted data then go back
333 		if (encryptedContent == null || encryptedContent.length == 0)
334 			return 0;
335 
336 		String projectPassword = null;
337 		if (workspace != null)
338 		{
339 			projectPassword = workspace.getProjectPassword(soapuiProject.getName());
340 		}
341 		else
342 		{
343 			projectPassword = this.projectPassword;
344 		}
345 		if (projectPassword == null)
346 		{
347 			password = UISupport.promptPassword("Enter Password:", soapuiProject.getName());
348 		}
349 		else
350 		{
351 			password = projectPassword.toCharArray();
352 		}
353 		byte[] data = null;
354 		// no pass go back.
355 		if (password == null)
356 		{
357 			return -1;
358 		}
359 
360 		try
361 		{
362 			data = OpenSSL.decrypt("des3", password, encryptedContent);
363 		}
364 		catch (IOException e)
365 		{
366 			// TODO Auto-generated catch block
367 			e.printStackTrace();
368 			return -1;
369 		}
370 		catch (GeneralSecurityException e)
371 		{
372 			// TODO Auto-generated catch block
373 			e.printStackTrace();
374 			return -1;
375 		}
376 		String decryptedData = new String(data, "UTF-8");
377 
378 		if (decryptedData != null)
379 		{
380 			if (decryptedData.length() > 0)
381 			{
382 				try
383 				{
384 					projectDocument.getSoapuiProject().set(XmlObject.Factory.parse(decryptedData));
385 				}
386 				catch (XmlException e)
387 				{
388 					UISupport.showErrorMessage("Wrong password. Project need to be reloaded.");
389 					getWorkspace().clearProjectPassword(soapuiProject.getName());
390 					return -1;
391 				}
392 			}
393 		}
394 		else
395 		{
396 			UISupport.showErrorMessage("Wrong project password");
397 			getWorkspace().clearProjectPassword(soapuiProject.getName());
398 			return -1;
399 		}
400 		projectDocument.getSoapuiProject().setEncryptedContent(null);
401 		return 1;
402 	}
403 
404 	@Override
405 	public void afterLoad()
406 	{
407 		super.afterLoad();
408 
409 		try
410 		{
411 			runAfterLoadScript();
412 		}
413 		catch (Exception e)
414 		{
415 			SoapUI.logError(e);
416 		}
417 	}
418 
419 	protected void setProjectRoot(String path)
420 	{
421 		if (path != null && projectDocument != null)
422 		{
423 			int ix = path.lastIndexOf(File.separatorChar);
424 			if (ix > 0)
425 				getSettings().setString(ProjectSettings.PROJECT_ROOT, path.substring(0, ix));
426 		}
427 	}
428 
429 	public void setResourceRoot(String resourceRoot)
430 	{
431 		String old = getResourceRoot();
432 
433 		getConfig().setResourceRoot(resourceRoot);
434 		notifyPropertyChanged(RESOURCE_ROOT_PROPERTY, old, resourceRoot);
435 	}
436 
437 	public String getResourceRoot()
438 	{
439 		if (!getConfig().isSetResourceRoot())
440 			getConfig().setResourceRoot("");
441 
442 		return getConfig().getResourceRoot();
443 	}
444 
445 	@Override
446 	public ImageIcon getIcon()
447 	{
448 		if (isDisabled())
449 			return disabledIcon;
450 		else if (getEncrypted() != 0)
451 		{
452 			if (isOpen())
453 			{
454 				return openEncyptedIcon;
455 			}
456 			else
457 			{
458 				return closedEncyptedIcon;
459 			}
460 		}
461 		else if (!isOpen())
462 			return closedIcon;
463 		else if (isRemote())
464 			return remoteIcon;
465 		else
466 			return super.getIcon();
467 	}
468 
469 	private String getNameFromPath()
470 	{
471 		int ix = path.lastIndexOf(isRemote() ? '/' : File.separatorChar);
472 		String name = ix == -1 ? path : path.substring(ix + 1);
473 		return name;
474 	}
475 
476 	@Override
477 	public String getDescription()
478 	{
479 		if (isOpen())
480 			return super.getDescription();
481 
482 		String name = getName();
483 
484 		if (isDisabled())
485 			name += " - disabled";
486 		else
487 			name += " - closed";
488 
489 		return name;
490 	}
491 
492 	public WorkspaceImpl getWorkspace()
493 	{
494 		return workspace;
495 	}
496 
497 	public AbstractInterface<?> getInterfaceAt(int index)
498 	{
499 		return interfaces.get(index);
500 	}
501 
502 	public AbstractInterface<?> getInterfaceByName(String interfaceName)
503 	{
504 		return (AbstractInterface<?>) getWsdlModelItemByName(interfaces, interfaceName);
505 	}
506 
507 	public AbstractInterface<?> getInterfaceByTechnicalId(String technicalId)
508 	{
509 		for (int c = 0; c < getInterfaceCount(); c++)
510 		{
511 			if (getInterfaceAt(c).getTechnicalId().equals(technicalId))
512 				return getInterfaceAt(c);
513 		}
514 
515 		return null;
516 	}
517 
518 	public int getInterfaceCount()
519 	{
520 		return interfaces.size();
521 	}
522 
523 	public String getPath()
524 	{
525 		return path;
526 	}
527 
528    public boolean save() throws IOException
529    {
530       return save( null );
531    }
532 
533 	public boolean save( String folder ) throws IOException
534 	{
535 		if (!isOpen() || isDisabled() || isRemote())
536 			return true;
537 
538 		if (path == null || isRemote())
539 		{
540 			path = getName() + "-soapui-project.xml";
541          if( folder != null )
542          {
543             path = folder + File.separatorChar + path;
544          }
545 
546 			File file = null;
547 
548 			while (file == null
549 					|| (file.exists() && !UISupport.confirm("File [" + file.getName() + "] exists, overwrite?",
550 							"Overwrite File?")))
551 			{
552 				file = UISupport.getFileDialogs().saveAs(this, "Save project " + getName(), ".xml", "XML Files (*.xml)",
553 						new File(path));
554 				if (file == null)
555 					return false;
556 			}
557 
558 			path = file.getAbsolutePath();
559 		}
560 
561 		File projectFile = new File(path);
562 
563 		while (projectFile.exists() && !projectFile.canWrite())
564 		{
565 			if (UISupport.confirm("Project file [" + path + "] can not be written to, save to new file?", "Save Project"))
566 			{
567 				projectFile = UISupport.getFileDialogs().saveAs(this, "Save project " + getName(), ".xml",
568 						"XML Files (*.xml)", projectFile);
569 
570 				if (projectFile == null)
571 					return false;
572 
573 				path = projectFile.getAbsolutePath();
574 			}
575 			else
576 				return false;
577 		}
578 
579 		// check modified
580 		if (projectFile.exists() && lastModified != 0 && lastModified < projectFile.lastModified())
581 		{
582 			if (!UISupport.confirm("Project file for [" + getName() + "] has been modified externally, overwrite?",
583 					"Save Project"))
584 				return false;
585 		}
586 
587 		if (projectFile.exists() && getSettings().getBoolean(UISettings.CREATE_BACKUP))
588 		{
589 			createBackup(projectFile);
590 		}
591 
592 		return saveIn(projectFile);
593 	}
594 
595 	public boolean saveBackup() throws IOException
596 	{
597 		File projectFile;
598 		if (path == null || isRemote())
599 		{
600 			projectFile = new File(getName() + "-soapui-project.xml");
601 		}
602 		else
603 		{
604 			projectFile = new File(path);
605 		}
606 		File backupFile = getBackupFile(projectFile);
607 		return saveIn(backupFile);
608 	}
609 
610 	public boolean saveIn(File projectFile) throws IOException
611 	{
612 		long size = 0;
613 
614 		beforeSave();
615 		// work with copy beacuse we do not want to change working project while
616 		// working with it
617 		// if user choose save project, save all etc.
618 		SoapuiProjectDocumentConfig projectDocument = (SoapuiProjectDocumentConfig) this.projectDocument.copy();
619 		// check for encryption
620 		String passwordForEncryption = getSettings().getString(ProjectSettings.SHADOW_PASSWORD, null);
621 		// if it has encryptedContend that means it is not decrypted corectly( bad
622 		// password, etc ), so do not encrypt it again.
623 		if (projectDocument.getSoapuiProject().getEncryptedContent() == null)
624 		{
625 			if (passwordForEncryption != null)
626 			{
627 				if (passwordForEncryption.length() > 1)
628 				{
629 					// we have password so do encryption
630 					try
631 					{
632 						String data = getConfig().xmlText();
633 						byte[] encrypted = OpenSSL.encrypt("des3", passwordForEncryption.toCharArray(), data.getBytes());
634 						projectDocument.getSoapuiProject().setEncryptedContent(encrypted);
635 						projectDocument.getSoapuiProject().setInterfaceArray(null);
636 						projectDocument.getSoapuiProject().setTestSuiteArray(null);
637 						projectDocument.getSoapuiProject().setMockServiceArray(null);
638 						projectDocument.getSoapuiProject().unsetSettings();
639 						projectDocument.getSoapuiProject().unsetProperties();
640 
641 					}
642 					catch (GeneralSecurityException e)
643 					{
644 						UISupport.showErrorMessage("Encryption Error");
645 					}
646 				}
647 				else
648 				{
649 					// no password no encryption.
650 					projectDocument.getSoapuiProject().setEncryptedContent(null);
651 				}
652 			}
653 		}
654 		// end of encryption.
655 
656 		XmlOptions options = new XmlOptions();
657 		if (SoapUI.getSettings().getBoolean(WsdlSettings.PRETTY_PRINT_PROJECT_FILES))
658 			options.setSavePrettyPrint();
659 
660 		// check for caching
661 		if (!getSettings().getBoolean(WsdlSettings.CACHE_WSDLS))
662 		{
663 			// no caching -> create copy and remove definition cachings
664 			SoapuiProjectDocumentConfig config = (SoapuiProjectDocumentConfig) projectDocument.copy();
665 			removeDefinitionCaches(config);
666 
667 			config.getSoapuiProject().setSoapuiVersion(SoapUI.SOAPUI_VERSION);
668 			ByteArrayOutputStream writer = new ByteArrayOutputStream(8192);
669 			config.save(writer, options);
670 			FileOutputStream out = new FileOutputStream(projectFile);
671 			writer.writeTo(out);
672 			out.close();
673 			size = writer.size();
674 		}
675 		else
676 		{
677 			try
678 			{
679 				// save to temporary buffer to avoid corruption of file
680 				projectDocument.getSoapuiProject().setSoapuiVersion(SoapUI.SOAPUI_VERSION);
681 				ByteArrayOutputStream writer = new ByteArrayOutputStream(8192);
682 				projectDocument.save(writer, options);
683 				FileOutputStream out = new FileOutputStream(projectFile);
684 				writer.writeTo(out);
685 				out.close();
686 				size = writer.size();
687 			}
688 			catch (Throwable t)
689 			{
690 				SoapUI.logError(t);
691 				UISupport.showErrorMessage("Failed to save project [" + getName() + "]: " + t.toString());
692 				return false;
693 			}
694 		}
695 
696 		lastModified = projectFile.lastModified();
697 		log.info("Saved project [" + getName() + "] to [" + projectFile.getAbsolutePath() + " - " + size + " bytes");
698 		setProjectRoot(path);
699 		return true;
700 	}
701 
702 	public void beforeSave()
703 	{
704 		try
705 		{
706 			runBeforeSaveScript();
707 		}
708 		catch (Exception e)
709 		{
710 			SoapUI.logError(e);
711 		}
712 
713 		// notify
714 		for (AbstractInterface<?> iface : interfaces)
715 			iface.beforeSave();
716 
717 		for (WsdlTestSuite testSuite : testSuites)
718 			testSuite.beforeSave();
719 
720 		for (WsdlMockService mockService : mockServices)
721 			mockService.beforeSave();
722 
723 		endpointStrategy.onSave();
724 	}
725 
726 	protected void createBackup(File projectFile) throws IOException
727 	{
728 		File backupFile = getBackupFile(projectFile);
729 		log.info("Backing up [" + projectFile + "] to [" + backupFile + "]");
730 		Tools.copyFile(projectFile, backupFile, true);
731 	}
732 
733 	protected File getBackupFile(File projectFile)
734 	{
735 		String backupFolderName = getSettings().getString(UISettings.BACKUP_FOLDER, "");
736 
737 		File backupFolder = new File(backupFolderName);
738 		if (!backupFolder.isAbsolute())
739 		{
740 			backupFolder = new File(projectFile.getParentFile(), backupFolderName);
741 		}
742 
743 		if (!backupFolder.exists())
744 			backupFolder.mkdirs();
745 
746 		File backupFile = new File(backupFolder, projectFile.getName() + ".backup");
747 		return backupFile;
748 	}
749 
750 	protected void removeDefinitionCaches(SoapuiProjectDocumentConfig config)
751 	{
752 		for (InterfaceConfig ifaceConfig : config.getSoapuiProject().getInterfaceList())
753 		{
754 			if (ifaceConfig.isSetDefinitionCache())
755 			{
756 				log.info("Removing definition cache from interface [" + ifaceConfig.getName() + "]");
757 				ifaceConfig.unsetDefinitionCache();
758 			}
759 		}
760 	}
761 
762 	public AbstractInterface<?> addNewInterface(String name, String type)
763 	{
764 		AbstractInterface<?> iface = (AbstractInterface<?>) InterfaceFactoryRegistry.createNew(this, type, name);
765 		if (iface != null)
766 		{
767 			iface.getConfig().setType(type);
768 
769 			interfaces.add(iface);
770 			fireInterfaceAdded(iface);
771 		}
772 
773 		return iface;
774 	}
775 
776 	public void addProjectListener(ProjectListener listener)
777 	{
778 		projectListeners.add(listener);
779 	}
780 
781 	public void removeProjectListener(ProjectListener listener)
782 	{
783 		projectListeners.remove(listener);
784 	}
785 
786 	public void fireInterfaceAdded(AbstractInterface<?> iface)
787 	{
788 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
789 
790 		for (int c = 0; c < a.length; c++)
791 		{
792 			a[c].interfaceAdded(iface);
793 		}
794 	}
795 
796 	public void fireInterfaceRemoved(AbstractInterface<?> iface)
797 	{
798 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
799 
800 		for (int c = 0; c < a.length; c++)
801 		{
802 			a[c].interfaceRemoved(iface);
803 		}
804 	}
805 
806 	public void fireInterfaceUpdated(AbstractInterface<?> iface)
807 	{
808 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
809 
810 		for (int c = 0; c < a.length; c++)
811 		{
812 			a[c].interfaceUpdated(iface);
813 		}
814 	}
815 
816 	public void fireTestSuiteAdded(WsdlTestSuite testSuite)
817 	{
818 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
819 
820 		for (int c = 0; c < a.length; c++)
821 		{
822 			a[c].testSuiteAdded(testSuite);
823 		}
824 	}
825 
826 	public void fireTestSuiteRemoved(WsdlTestSuite testSuite)
827 	{
828 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
829 
830 		for (int c = 0; c < a.length; c++)
831 		{
832 			a[c].testSuiteRemoved(testSuite);
833 		}
834 	}
835 
836 	public void fireMockServiceAdded(WsdlMockService mockService)
837 	{
838 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
839 
840 		for (int c = 0; c < a.length; c++)
841 		{
842 			a[c].mockServiceAdded(mockService);
843 		}
844 	}
845 
846 	public void fireMockServiceRemoved(WsdlMockService mockService)
847 	{
848 		ProjectListener[] a = projectListeners.toArray(new ProjectListener[projectListeners.size()]);
849 
850 		for (int c = 0; c < a.length; c++)
851 		{
852 			a[c].mockServiceRemoved(mockService);
853 		}
854 	}
855 
856 	public void removeInterface(AbstractInterface<?> iface)
857 	{
858 		int ix = interfaces.indexOf(iface);
859 		interfaces.remove(ix);
860 		try
861 		{
862 			fireInterfaceRemoved(iface);
863 		}
864 		finally
865 		{
866 			iface.release();
867 			getConfig().removeInterface(ix);
868 		}
869 	}
870 
871 	public void removeTestSuite(WsdlTestSuite testSuite)
872 	{
873 		int ix = testSuites.indexOf(testSuite);
874 		testSuites.remove(ix);
875 
876 		try
877 		{
878 			fireTestSuiteRemoved(testSuite);
879 		}
880 		finally
881 		{
882 			testSuite.release();
883 			getConfig().removeTestSuite(ix);
884 		}
885 	}
886 
887 	public boolean isDisabled()
888 	{
889 		return disabled;
890 	}
891 
892 	public int getTestSuiteCount()
893 	{
894 		return testSuites.size();
895 	}
896 
897 	public WsdlTestSuite getTestSuiteAt(int index)
898 	{
899 		return testSuites.get(index);
900 	}
901 
902 	public WsdlTestSuite getTestSuiteByName(String testSuiteName)
903 	{
904 		return (WsdlTestSuite) getWsdlModelItemByName(testSuites, testSuiteName);
905 	}
906 
907 	public WsdlTestSuite addNewTestSuite(String name)
908 	{
909 		WsdlTestSuite testSuite = new WsdlTestSuite(this, getConfig().addNewTestSuite());
910 		testSuite.setName(name);
911 		testSuites.add(testSuite);
912 		fireTestSuiteAdded(testSuite);
913 
914 		return testSuite;
915 	}
916 
917 	public boolean isCacheDefinitions()
918 	{
919 		return getSettings().getBoolean(WsdlSettings.CACHE_WSDLS);
920 	}
921 
922 	public void setCacheDefinitions(boolean cacheDefinitions)
923 	{
924 		getSettings().setBoolean(WsdlSettings.CACHE_WSDLS, cacheDefinitions);
925 	}
926 
927 	public boolean saveAs(String fileName) throws IOException
928 	{
929 		if (!isOpen() || isDisabled())
930 			return false;
931 
932 		String oldPath = path;
933 		path = fileName;
934 		boolean result = save();
935 		if (!result)
936 			path = oldPath;
937 		else
938 			remote = false;
939 
940 		setProjectRoot(path);
941 
942 		return result;
943 	}
944 
945 	@Override
946 	public void release()
947 	{
948 		super.release();
949 
950 		if (isOpen())
951 		{
952 			endpointStrategy.release();
953 
954 			for (WsdlTestSuite testSuite : testSuites)
955 				testSuite.release();
956 
957 			for (WsdlMockService mockService : mockServices)
958 				mockService.release();
959 
960 			for (AbstractInterface<?> iface : interfaces)
961 				iface.release();
962 		}
963 
964 		projectListeners.clear();
965 
966 		if (afterLoadScriptEngine != null)
967 			afterLoadScriptEngine.release();
968 
969 		if (beforeSaveScriptEngine != null)
970 			beforeSaveScriptEngine.release();
971 	}
972 
973 	public WsdlMockService addNewMockService(String name)
974 	{
975 		WsdlMockService mockService = new WsdlMockService(this, getConfig().addNewMockService());
976 		mockService.setName(name);
977 		mockServices.add(mockService);
978 		fireMockServiceAdded(mockService);
979 
980 		return mockService;
981 	}
982 
983 	public WsdlMockService getMockServiceAt(int index)
984 	{
985 		return mockServices.get(index);
986 	}
987 
988 	public WsdlMockService getMockServiceByName(String mockServiceName)
989 	{
990 		return (WsdlMockService) getWsdlModelItemByName(mockServices, mockServiceName);
991 	}
992 
993 	public int getMockServiceCount()
994 	{
995 		return mockServices.size();
996 	}
997 
998 	public void removeMockService(WsdlMockService mockService)
999 	{
1000 		int ix = mockServices.indexOf(mockService);
1001 		mockServices.remove(ix);
1002 
1003 		try
1004 		{
1005 			fireMockServiceRemoved(mockService);
1006 		}
1007 		finally
1008 		{
1009 			mockService.release();
1010 			getConfig().removeMockService(ix);
1011 		}
1012 	}
1013 
1014 	public List<TestSuite> getTestSuiteList()
1015 	{
1016 		return new ArrayList<TestSuite>(testSuites);
1017 	}
1018 
1019 	public List<MockService> getMockServiceList()
1020 	{
1021 		return new ArrayList<MockService>(mockServices);
1022 	}
1023 
1024 	public List<Interface> getInterfaceList()
1025 	{
1026 		return new ArrayList<Interface>(interfaces);
1027 	}
1028 
1029 	public Map<String, Interface> getInterfaces()
1030 	{
1031 		Map<String, Interface> result = new HashMap<String, Interface>();
1032 		for (Interface iface : interfaces)
1033 			result.put(iface.getName(), iface);
1034 
1035 		return result;
1036 	}
1037 
1038 	public Map<String, TestSuite> getTestSuites()
1039 	{
1040 		Map<String, TestSuite> result = new HashMap<String, TestSuite>();
1041 		for (TestSuite iface : testSuites)
1042 			result.put(iface.getName(), iface);
1043 
1044 		return result;
1045 	}
1046 
1047 	public Map<String, MockService> getMockServices()
1048 	{
1049 		Map<String, MockService> result = new HashMap<String, MockService>();
1050 		for (MockService mockService : mockServices)
1051 			result.put(mockService.getName(), mockService);
1052 
1053 		return result;
1054 	}
1055 
1056 	public void reload() throws SoapUIException
1057 	{
1058 		reload(path);
1059 	}
1060 
1061 	public void reload(String path) throws SoapUIException
1062 	{
1063 		this.path = path;
1064 		getWorkspace().reloadProject(this);
1065 	}
1066 
1067 	public boolean hasNature(String natureId)
1068 	{
1069 		Settings projectSettings = getSettings();
1070 		String projectNature = projectSettings.getString(ProjectSettings.PROJECT_NATURE, null);
1071 		return natureId.equals(projectNature);
1072 	}
1073 
1074 	public AbstractInterface<?> importInterface(AbstractInterface<?> iface, boolean importEndpoints, boolean createCopy)
1075 	{
1076 		iface.beforeSave();
1077 
1078 		InterfaceConfig ifaceConfig = (InterfaceConfig) iface.getConfig().copy();
1079 		AbstractInterface<?> imported = InterfaceFactoryRegistry.build(this, ifaceConfig);
1080 		if (ifaceConfig.isSetId() && createCopy)
1081 			ifaceConfig.unsetId();
1082 
1083 		interfaces.add(imported);
1084 
1085 		if (iface.getProject() != this && importEndpoints)
1086 		{
1087 			endpointStrategy.importEndpoints(iface);
1088 		}
1089 
1090 		imported.afterLoad();
1091 		fireInterfaceAdded(imported);
1092 
1093 		return imported;
1094 	}
1095 
1096 	public WsdlTestSuite importTestSuite(WsdlTestSuite testSuite, String name, boolean createCopy)
1097 	{
1098 		testSuite.beforeSave();
1099 		TestSuiteConfig testSuiteConfig = (TestSuiteConfig) getConfig().addNewTestSuite().set(
1100 				testSuite.getConfig().copy());
1101 		testSuiteConfig.setName(name);
1102 		if (testSuiteConfig.isSetId() && createCopy)
1103 			testSuiteConfig.unsetId();
1104 
1105 		testSuite = new WsdlTestSuite(this, testSuiteConfig);
1106 		testSuites.add(testSuite);
1107 		testSuite.afterLoad();
1108 		fireTestSuiteAdded(testSuite);
1109 
1110       resolveImportedTestSuite( testSuite );
1111 
1112 		return testSuite;
1113 	}
1114 
1115 	public WsdlMockService importMockService(WsdlMockService mockService, String name, boolean createCopy)
1116 	{
1117 		mockService.beforeSave();
1118 		MockServiceConfig mockServiceConfig = (MockServiceConfig) getConfig().addNewMockService().set(
1119 				mockService.getConfig().copy());
1120 		mockServiceConfig.setName(name);
1121 		if (mockServiceConfig.isSetId() && createCopy)
1122 			mockServiceConfig.unsetId();
1123 		mockService = new WsdlMockService(this, mockServiceConfig);
1124 		mockServices.add(mockService);
1125 		mockService.afterLoad();
1126 
1127 		fireMockServiceAdded(mockService);
1128 
1129 		return mockService;
1130 	}
1131 
1132 	public EndpointStrategy getEndpointStrategy()
1133 	{
1134 		return endpointStrategy;
1135 	}
1136 
1137 	public boolean isOpen()
1138 	{
1139 		return open;
1140 	}
1141 
1142 	public List<? extends ModelItem> getChildren()
1143 	{
1144 		ArrayList<ModelItem> list = new ArrayList<ModelItem>();
1145 		list.addAll(getInterfaceList());
1146 		list.addAll(getTestSuiteList());
1147 		list.addAll(getMockServiceList());
1148 		return list;
1149 	}
1150 
1151 	public void setAfterLoadScript(String script)
1152 	{
1153 		String oldScript = getAfterLoadScript();
1154 
1155 		if (!getConfig().isSetAfterLoadScript())
1156 			getConfig().addNewAfterLoadScript();
1157 
1158 		getConfig().getAfterLoadScript().setStringValue(script);
1159 		if (afterLoadScriptEngine != null)
1160 			afterLoadScriptEngine.setScript(script);
1161 
1162 		notifyPropertyChanged(AFTER_LOAD_SCRIPT_PROPERTY, oldScript, script);
1163 	}
1164 
1165 	public String getAfterLoadScript()
1166 	{
1167 		return getConfig().isSetAfterLoadScript() ? getConfig().getAfterLoadScript().getStringValue() : null;
1168 	}
1169 
1170 	public void setBeforeSaveScript(String script)
1171 	{
1172 		String oldScript = getBeforeSaveScript();
1173 
1174 		if (!getConfig().isSetBeforeSaveScript())
1175 			getConfig().addNewBeforeSaveScript();
1176 
1177 		getConfig().getBeforeSaveScript().setStringValue(script);
1178 		if (beforeSaveScriptEngine != null)
1179 			beforeSaveScriptEngine.setScript(script);
1180 
1181 		notifyPropertyChanged(BEFORE_SAVE_SCRIPT_PROPERTY, oldScript, script);
1182 	}
1183 
1184 	public String getBeforeSaveScript()
1185 	{
1186 		return getConfig().isSetBeforeSaveScript() ? getConfig().getBeforeSaveScript().getStringValue() : null;
1187 	}
1188 
1189 	public Object runAfterLoadScript() throws Exception
1190 	{
1191 		String script = getAfterLoadScript();
1192 		if (StringUtils.isNullOrEmpty(script))
1193 			return null;
1194 
1195 		if (afterLoadScriptEngine == null)
1196 		{
1197 			afterLoadScriptEngine = SoapUIScriptEngineRegistry.create(SoapUIScriptEngineRegistry.GROOVY_ID, this);
1198 			afterLoadScriptEngine.setScript(script);
1199 		}
1200 
1201 		afterLoadScriptEngine.setVariable("context", context);
1202 		afterLoadScriptEngine.setVariable("project", this);
1203 		afterLoadScriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
1204 		return afterLoadScriptEngine.run();
1205 	}
1206 
1207 	public Object runBeforeSaveScript() throws Exception
1208 	{
1209 		String script = getBeforeSaveScript();
1210 		if (StringUtils.isNullOrEmpty(script))
1211 			return null;
1212 
1213 		if (beforeSaveScriptEngine == null)
1214 		{
1215 			beforeSaveScriptEngine = SoapUIScriptEngineRegistry.create(SoapUIScriptEngineRegistry.GROOVY_ID, this);
1216 			beforeSaveScriptEngine.setScript(script);
1217 		}
1218 
1219 		beforeSaveScriptEngine.setVariable("context", context);
1220 		beforeSaveScriptEngine.setVariable("project", this);
1221 		beforeSaveScriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
1222 		return beforeSaveScriptEngine.run();
1223 	}
1224 
1225 	public PropertyExpansionContext getContext()
1226 	{
1227 		return context;
1228 	}
1229 
1230 	public DefaultWssContainer getWssContainer()
1231 	{
1232 		return wssContainer;
1233 	}
1234 
1235 	@Override
1236 	public void resolve(ResolveContext context)
1237 	{
1238 		super.resolve(context);
1239 
1240 		wssContainer.resolve(context);
1241 	}
1242 
1243 	public PropertyExpansion[] getPropertyExpansions()
1244 	{
1245 		return wssContainer.getPropertyExpansions();
1246 	}
1247 
1248 	public String getPropertiesLabel()
1249 	{
1250 		return "Custom Properties";
1251 	}
1252 
1253 	public String getShadowPassword()
1254 	{
1255 		projectPassword = getSettings() == null ? projectPassword : getSettings().getString(
1256 				ProjectSettings.SHADOW_PASSWORD, null);
1257 		return projectPassword;
1258 	}
1259 
1260 	public void setShadowPassword(String password)
1261 	{
1262 		String oldPassword = getSettings().getString(ProjectSettings.SHADOW_PASSWORD, null);
1263 		getSettings().setString(ProjectSettings.SHADOW_PASSWORD, password);
1264 		this.pcs.firePropertyChange("projectPassword", oldPassword, password);
1265 	}
1266 
1267 	public void inspect()
1268 	{
1269 
1270 		if (!isOpen())
1271 			return;
1272 
1273 		byte data[] = projectDocument.getSoapuiProject().getEncryptedContent();
1274 		if (data != null && data.length > 0)
1275 		{
1276 			try
1277 			{
1278 				reload();
1279 			}
1280 			catch (SoapUIException e)
1281 			{
1282 				e.printStackTrace();
1283 			}
1284 		}
1285 	}
1286 
1287 	public int getEncrypted()
1288 	{
1289 		return this.encrypted;
1290 	}
1291 
1292 	public int setEncrypted(int code)
1293 	{
1294 		return this.encrypted = code;
1295 	}
1296 
1297 	public void addPropertyChangeListener(PropertyChangeListener listener)
1298 	{
1299 		this.pcs.addPropertyChangeListener(listener);
1300 	}
1301 
1302 	public void propertyChange(PropertyChangeEvent evt)
1303 	{
1304 		if ("projectPassword".equals(evt.getPropertyName()))
1305 		{
1306 			if (encrypted == 0 & (evt.getOldValue() == null || ((String) evt.getOldValue()).length() == 0))
1307 			{
1308 				encrypted = 1;
1309 			}
1310 			if (encrypted == 1 & (evt.getNewValue() == null || ((String) evt.getNewValue()).length() == 0))
1311 			{
1312 				encrypted = 0;
1313 			}
1314 			SoapUI.getNavigator().repaint();
1315 		}
1316 
1317 	}
1318 
1319 	public SoapuiProjectDocumentConfig getProjectDocument()
1320 	{
1321 		return projectDocument;
1322 	}
1323 
1324 	public int getInterfaceCount(String type)
1325 	{
1326 		int result = 0;
1327 
1328 		for (AbstractInterface iface : interfaces)
1329 		{
1330 			if (iface.getType().equals(type))
1331 				result++;
1332 		}
1333 
1334 		return result;
1335 	}
1336 
1337 	public List<AbstractInterface> getInterfaces(String type)
1338 	{
1339 		ArrayList<AbstractInterface> result = new ArrayList<AbstractInterface>();
1340 
1341 		for (AbstractInterface iface : interfaces)
1342 		{
1343 			if (iface.getType().equals(type))
1344 				result.add(iface);
1345 		}
1346 
1347 		return result;
1348 	}
1349 
1350 	public void importTestSuite(File file)
1351 	{
1352 		if (!file.exists())
1353 		{
1354 			UISupport.showErrorMessage("Error loading test case ");
1355 			return;
1356 		}
1357 
1358 		TestSuiteDocumentConfig newTestSuiteConfig = null;
1359 
1360 		try
1361 		{
1362 			newTestSuiteConfig = TestSuiteDocumentConfig.Factory.parse(file);
1363 		}
1364 		catch (Exception e)
1365 		{
1366 			SoapUI.logError(e);
1367 		}
1368 
1369 		if (newTestSuiteConfig == null)
1370 		{
1371 			UISupport.showErrorMessage("Not valild test case xml");
1372 		}
1373 		else
1374 		{
1375 			WsdlTestSuite testSuite = new WsdlTestSuite(this, newTestSuiteConfig.getTestSuite());
1376 			projectDocument.getSoapuiProject().addNewTestSuite().set(testSuite.getConfig());
1377 			testSuite.afterLoad();
1378 			
1379 			testSuites.add(testSuite);
1380 			fireTestSuiteAdded(testSuite);
1381 
1382          resolveImportedTestSuite( testSuite );
1383 		}
1384 	}
1385 
1386    private void resolveImportedTestSuite( WsdlTestSuite testSuite )
1387    {
1388       ResolveDialog resolver = new ResolveDialog( "Validate TestSuite", "Checks TestSuite for inconsistencies", null);
1389       resolver.setShowOkMessage( false );
1390       resolver.resolve( testSuite );
1391    }
1392 }