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