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