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;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.config.SoapuiWorkspaceDocumentConfig;
17  import com.eviware.soapui.config.WorkspaceProjectConfig;
18  import com.eviware.soapui.config.WorkspaceProjectConfig.Status;
19  import com.eviware.soapui.config.WorkspaceProjectConfig.Type;
20  import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
21  import com.eviware.soapui.impl.wsdl.WsdlProject;
22  import com.eviware.soapui.impl.wsdl.WsdlProjectFactory;
23  import com.eviware.soapui.impl.wsdl.support.PathUtils;
24  import com.eviware.soapui.model.ModelItem;
25  import com.eviware.soapui.model.project.Project;
26  import com.eviware.soapui.model.project.ProjectFactoryRegistry;
27  import com.eviware.soapui.model.settings.Settings;
28  import com.eviware.soapui.model.support.AbstractModelItem;
29  import com.eviware.soapui.model.workspace.Workspace;
30  import com.eviware.soapui.model.workspace.WorkspaceListener;
31  import com.eviware.soapui.settings.UISettings;
32  import com.eviware.soapui.support.MessageSupport;
33  import com.eviware.soapui.support.SoapUIException;
34  import com.eviware.soapui.support.UISupport;
35  import com.eviware.soapui.support.resolver.ResolveDialog;
36  import com.eviware.soapui.support.types.StringToStringMap;
37  import org.apache.log4j.Logger;
38  import org.apache.xmlbeans.XmlException;
39  import org.apache.xmlbeans.XmlOptions;
40  
41  import javax.swing.*;
42  import java.io.File;
43  import java.io.IOException;
44  import java.util.*;
45  
46  /***
47   * Default Workspace implementation
48   *
49   * @author Ole.Matzura
50   */
51  
52  public class WorkspaceImpl extends AbstractModelItem implements Workspace
53  {
54     private final static Logger log = Logger.getLogger( WorkspaceImpl.class );
55     public static final MessageSupport messages = MessageSupport.getMessages( WorkspaceImpl.class );
56  
57     private List<Project> projectList = new ArrayList<Project>();
58     private SoapuiWorkspaceDocumentConfig workspaceConfig;
59     private String path = null;
60     private Set<WorkspaceListener> listeners = new HashSet<WorkspaceListener>();
61     private ImageIcon workspaceIcon;
62     private XmlBeansSettingsImpl settings;
63     private StringToStringMap projectOptions;
64     private ResolveDialog resolver;
65  
66     public WorkspaceImpl( String path, StringToStringMap projectOptions ) throws XmlException, IOException
67     {
68        if( projectOptions == null )
69        {
70           this.projectOptions = new StringToStringMap();
71        }
72        else
73        {
74           this.projectOptions = projectOptions;
75        }
76        File file = new File( path );
77        this.path = file.getAbsolutePath();
78        loadWorkspace( file );
79        workspaceIcon = UISupport.createImageIcon( "/workspace.gif" );
80     }
81  
82     public void switchWorkspace( File file ) throws SoapUIException
83     {
84        // check first if valid workspace file
85        if( file.exists() )
86        {
87           try
88           {
89              SoapuiWorkspaceDocumentConfig.Factory.parse( file );
90           }
91           catch( Exception e )
92           {
93              throw new SoapUIException( messages.get( "FailedToLoadWorkspaceException" ) + e.toString() );
94           }
95        }
96  
97        fireWorkspaceSwitching();
98  
99        while( projectList.size() > 0 )
100       {
101          Project project = projectList.remove( 0 );
102          try
103          {
104             fireProjectRemoved( project );
105          }
106          finally
107          {
108             project.release();
109          }
110       }
111 
112       try
113       {
114          String oldName = getName();
115 
116          loadWorkspace( file );
117          this.path = file.getAbsolutePath();
118 
119          for( Project project : projectList )
120          {
121             fireProjectAdded( project );
122          }
123 
124          notifyPropertyChanged( ModelItem.NAME_PROPERTY, oldName, getName() );
125       }
126       catch( Exception e )
127       {
128          SoapUI.logError( e );
129       }
130 
131       fireWorkspaceSwitched();
132    }
133 
134    public void loadWorkspace( File file ) throws XmlException, IOException
135    {
136       if( file.exists() )
137       {
138          log.info( messages.get( "FailedToLoadWorkspaceFrom", file.getAbsolutePath() ) );
139          workspaceConfig = SoapuiWorkspaceDocumentConfig.Factory.parse( file );
140          if( workspaceConfig.getSoapuiWorkspace().getSettings() == null )
141             workspaceConfig.getSoapuiWorkspace().addNewSettings();
142 
143          settings = new XmlBeansSettingsImpl( this, SoapUI.getSettings(), workspaceConfig
144                  .getSoapuiWorkspace().getSettings() );
145 
146          boolean closeOnStartup = getSettings().getBoolean( UISettings.CLOSE_PROJECTS );
147          List<WorkspaceProjectConfig> projects = workspaceConfig.getSoapuiWorkspace().getProjectList();
148          for( int i = 0; i < projects.size(); i++ )
149          {
150             WorkspaceProjectConfig wsc = projects.get( i );
151             String str = PathUtils.denormalizePath( wsc.getStringValue() );
152 
153             str = PathUtils.adjustRelativePath( str, getProjectRoot(), this );
154 
155             try
156             {
157 //					WsdlProject project = new WsdlProject( str, this, false, !closeOnStartup &&
158 //								wsc.getStatus() != Status.CLOSED && wsc.getType() != Type.REMOTE, wsc.getName(), null);
159                WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( str, this, false, !closeOnStartup &&
160                        wsc.getStatus() != Status.CLOSED && wsc.getType() != Type.REMOTE, wsc.getName(), null );
161 
162                projectList.add( project );
163             }
164             catch( Exception e )
165             {
166                UISupport.showErrorMessage( messages.get( "FailedToLoadProjectInWorkspace", str )
167                        + e.getMessage() );
168 
169                SoapUI.logError( e );
170             }
171          }
172       }
173       else
174       {
175          workspaceConfig = SoapuiWorkspaceDocumentConfig.Factory.newInstance();
176          workspaceConfig.addNewSoapuiWorkspace().setName( messages.get( "DefaultWorkspaceName" ) );
177          workspaceConfig.getSoapuiWorkspace().addNewSettings();
178 
179          settings = new XmlBeansSettingsImpl( this, SoapUI.getSettings(), workspaceConfig
180                  .getSoapuiWorkspace().getSettings() );
181       }
182    }
183 
184    public void setPath( String path )
185    {
186       this.path = path;
187    }
188 
189    public Project[] getProjects()
190    {
191       return projectList.toArray( new Project[projectList.size()] );
192    }
193 
194    public void setName( String name )
195    {
196       String oldName = getName();
197 
198       workspaceConfig.getSoapuiWorkspace().setName( name );
199       notifyPropertyChanged( ModelItem.NAME_PROPERTY, oldName, name );
200    }
201 
202    public void setDescription( String description )
203    {
204       String oldDescription = getDescription();
205 
206       workspaceConfig.getSoapuiWorkspace().setDescription( description );
207       notifyPropertyChanged( ModelItem.DESCRIPTION_PROPERTY, oldDescription, description );
208    }
209 
210    public String getName()
211    {
212       return workspaceConfig.getSoapuiWorkspace().isSetName() ? workspaceConfig.getSoapuiWorkspace().getName() : messages.get( "DefaultWorkspaceName" );
213    }
214 
215    public Project getProjectAt( int index )
216    {
217       return projectList.get( index );
218    }
219 
220    public Project getProjectByName( String projectName )
221    {
222       for( Project project : projectList )
223       {
224          if( project.getName().equals( projectName ) )
225             return project;
226       }
227 
228       return null;
229    }
230 
231    public int getProjectCount()
232    {
233       return projectList.size();
234    }
235 
236    public void onClose()
237    {
238       save( !getSettings().getBoolean( UISettings.AUTO_SAVE_PROJECTS_ON_EXIT ) );
239    }
240 
241    public void save( boolean workspaceOnly )
242    {
243       save( workspaceOnly, false );
244    }
245 
246    public void save( boolean workspaceOnly, boolean skipProjectsWithRunningTests )
247    {
248       try
249       {
250          // not saved?
251          if( path == null )
252          {
253             File file = UISupport.getFileDialogs().saveAs( this, messages.get( "SaveWorkspace.Title" ), ".xml",
254                     "XML Files (*.xml)", null );
255             if( file == null )
256                return;
257 
258             path = file.getAbsolutePath();
259          }
260 
261          List<WorkspaceProjectConfig> projects = new ArrayList<WorkspaceProjectConfig>();
262 
263          // save projects first
264          for( int c = 0; c < getProjectCount(); c++ )
265          {
266             WsdlProject project = (WsdlProject) getProjectAt( c );
267 
268             if( !workspaceOnly )
269             {
270                if( skipProjectsWithRunningTests && SoapUI.getTestMonitor().hasRunningTests( project ) )
271                {
272                   log.warn( messages.get( "ProjectHasRunningTests.Warning", project.getName() ) );
273                }
274                else
275                {
276                   String path = project.getPath();
277                   if( path == null )
278                   {
279                      if( UISupport.confirm( messages.get( "ProjectHasNotBeenSaved.Label", project.getName() ),
280                              messages.get( "ProjectHasNotBeenSaved.Title" ) ) )
281                      {
282                         project.save();
283                      }
284                   }
285                   else
286                   {
287                      project.save();
288                   }
289                }
290             }
291 
292             String path = project.getPath();
293             if( path != null )
294             {
295                path = PathUtils.createRelativePath( path, getProjectRoot(), this );
296 
297                WorkspaceProjectConfig wpc = WorkspaceProjectConfig.Factory.newInstance();
298                wpc.setStringValue( PathUtils.normalizePath( path ) );
299                if( project.isRemote() )
300                   wpc.setType( Type.REMOTE );
301 
302                if( !project.isOpen() )
303                {
304                   if( project.getEncrypted() == 0 )
305                   {
306                      wpc.setStatus( Status.CLOSED );
307                   }
308                   else
309                   {
310                      wpc.setStatus( Status.CLOSED_AND_ENCRYPTED );
311                   }
312                }
313 
314                wpc.setName( project.getName() );
315                projects.add( wpc );
316             }
317          }
318 
319          workspaceConfig.getSoapuiWorkspace().setProjectArray(
320                  projects.toArray( new WorkspaceProjectConfig[projects.size()] ) );
321          workspaceConfig.getSoapuiWorkspace().setSoapuiVersion( SoapUI.SOAPUI_VERSION );
322 
323          File workspaceFile = new File( path );
324          workspaceConfig.save( workspaceFile, new XmlOptions().setSavePrettyPrint() );
325 
326          log.info( messages.get( "SavedWorkspace.Info", workspaceFile.getAbsolutePath() ) ); //$NON-NLS-1$ //$NON-NLS-2$
327       }
328       catch( IOException e )
329       {
330          log.error( messages.get( "FailedToSaveWorkspace.Error" ) + e.getMessage(), e ); //$NON-NLS-1$
331       }
332    }
333 
334    public void addWorkspaceListener( WorkspaceListener listener )
335    {
336       listeners.add( listener );
337    }
338 
339    public void removeWorkspaceListener( WorkspaceListener listener )
340    {
341       listeners.remove( listener );
342    }
343 
344    public Project importProject( String fileName ) throws SoapUIException
345    {
346       File projectFile = new File( fileName );
347       WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( projectFile.getAbsolutePath(), this );
348 
349       projectList.add( project );
350       fireProjectAdded( project );
351 
352       resolveProject( project );
353 
354       save( true );
355 
356       return project;
357    }
358 
359    public void resolveProject( WsdlProject project )
360    {
361       if( resolver == null )
362       {
363          resolver = new ResolveDialog( "Resolve Project", "Resolve imported project", null );
364          resolver.setShowOkMessage( false );
365       }
366 
367       resolver.resolve( project );
368    }
369 
370    public WsdlProject createProject( String name ) throws SoapUIException
371    {
372       File projectFile = new File( createProjectFileName( name ) );
373       File file = UISupport.getFileDialogs().saveAs( this, messages.get( "CreateProject.Title" ), ".xml",
374               "XML Files (*.xml)", projectFile );
375       if( file == null )
376          return null;
377 
378       return createProject( name, file );
379    }
380 
381    public WsdlProject createProject( String name, File file ) throws SoapUIException
382    {
383       File projectFile = file;
384       while( projectFile != null && projectFile.exists() )
385       {
386          Boolean result = Boolean.FALSE;
387          while( !result.booleanValue() )
388          {
389             result = UISupport.confirmOrCancel( messages.get( "OverwriteProject.Label" ), messages.get( "OverwriteProject.Title" ) );
390             if( result == null )
391                return null;
392             if( result.booleanValue() )
393             {
394                projectFile.delete();
395             }
396             else
397             {
398                projectFile = UISupport.getFileDialogs().saveAs( this, messages.get( "CreateProject.Title" ), ".xml",
399                        "XML Files (*.xml)", projectFile ); //$NON-NLS-1$
400                if( projectFile == null )
401                   return null;
402                else
403                   break;
404             }
405          }
406       }
407 
408 //		WsdlProject project = new WsdlProject( projectFile == null ? null : projectFile.getAbsolutePath(), this );
409       WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory( WsdlProjectFactory.WSDL_TYPE ).createNew( projectFile == null ? null : projectFile.getAbsolutePath(), this );
410 
411       project.setName( name );
412       projectList.add( project );
413 
414       fireProjectAdded( project );
415 
416       try
417       {
418          if( projectFile != null )
419             project.save();
420       }
421       catch( IOException e )
422       {
423          log.error( messages.get( "FailedToSaveProject.Error" ) + e.getMessage(), e );
424       }
425 //		save( true );
426 
427       return project;
428    }
429 
430    private void fireProjectAdded( Project project )
431    {
432       for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
433       {
434          WorkspaceListener listener = iter.next();
435          listener.projectAdded( project );
436       }
437    }
438 
439    private void fireWorkspaceSwitching()
440    {
441       for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
442       {
443          WorkspaceListener listener = iter.next();
444          listener.workspaceSwitching( this );
445       }
446    }
447 
448    private void fireWorkspaceSwitched()
449    {
450       for( Iterator<WorkspaceListener> iter = listeners.iterator(); iter.hasNext(); )
451       {
452          WorkspaceListener listener = iter.next();
453          listener.workspaceSwitched( this );
454       }
455    }
456 
457    private String createProjectFileName( String name )
458    {
459       return name + "-soapui-project.xml"; //$NON-NLS-1$
460    }
461 
462    public void removeProject( Project project )
463    {
464       int ix = projectList.indexOf( project );
465       if( ix == -1 )
466          throw new RuntimeException( "Project [" + project.getName()
467                  + "] not available in workspace for removal" );
468 
469       projectList.remove( ix );
470 
471       try
472       {
473          fireProjectRemoved( project );
474       }
475       finally
476       {
477          project.release();
478 //			workspaceConfig.getSoapuiWorkspace().removeProject( ix );
479       }
480    }
481 
482    public Project reloadProject( Project project ) throws SoapUIException
483    {
484       int ix = projectList.indexOf( project );
485       if( ix == -1 )
486          throw new RuntimeException( "Project [" + project.getName() //$NON-NLS-1$
487                  + "] not available in workspace for reload" ); //$NON-NLS-1$
488 
489       projectList.remove( ix );
490       fireProjectRemoved( project );
491 
492       String tempName = project.getName();
493       project.release();
494       project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( project.getPath(), this, false, true, tempName, null );
495       projectList.add( ix, project );
496 
497       fireProjectAdded( project );
498 
499       return project;
500    }
501 
502    private void fireProjectRemoved( Project project )
503    {
504       WorkspaceListener[] listenerArray = listeners
505               .toArray( new WorkspaceListener[listeners.size()] );
506       for( int c = 0; c < listenerArray.length; c++ )
507       {
508          listenerArray[c].projectRemoved( project );
509       }
510    }
511 
512    public ImageIcon getIcon()
513    {
514       return workspaceIcon;
515    }
516 
517    public Settings getSettings()
518    {
519       return settings;
520    }
521 
522    public int getIndexOfProject( Project project )
523    {
524       return projectList.indexOf( project );
525    }
526 
527    public String getPath()
528    {
529       return path;
530    }
531 
532    public String getProjectRoot()
533    {
534       return workspaceConfig.getSoapuiWorkspace().getProjectRoot();
535    }
536 
537    public void setProjectRoot( String workspaceRoot )
538    {
539       workspaceConfig.getSoapuiWorkspace().setProjectRoot( workspaceRoot );
540    }
541 
542    public void release()
543    {
544       settings.release();
545 
546       for( Project project : projectList )
547          project.release();
548    }
549 
550    public List<? extends Project> getProjectList()
551    {
552       return projectList;
553    }
554 
555    public String getDescription()
556    {
557       return workspaceConfig.getSoapuiWorkspace().getDescription();
558    }
559 
560    public WsdlProject importRemoteProject( String url ) throws SoapUIException
561    {
562 //		WsdlProject project = new WsdlProject( url, this, false );
563       WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory( "wsdl" ).createNew( url, this, false );
564       projectList.add( project );
565       fireProjectAdded( project );
566 
567       resolveProject( project );
568 
569       save( true );
570 
571       return project;
572    }
573 
574    public void closeProject( Project project )
575    {
576       int oldProjectEncrypt = ( (WsdlProject) project ).getEncrypted();
577       int ix = projectList.indexOf( project );
578       if( ix == -1 )
579          throw new RuntimeException( "Project [" + project.getName()
580                  + "] not available in workspace for close" );
581 
582       projectList.remove( ix );
583       fireProjectRemoved( project );
584 
585       String name = project.getName();
586       project.release();
587 
588       try
589       {
590 //			project = new WsdlProject( project.getPath(), this, false, false, name, null );
591          project = ProjectFactoryRegistry.getProjectFactory( WsdlProjectFactory.WSDL_TYPE ).createNew( project.getPath(), this, false, false, name, null );
592          ( (WsdlProject) project ).setEncrypted( oldProjectEncrypt );
593          projectList.add( ix, project );
594          fireProjectAdded( project );
595       }
596       catch( Exception e )
597       {
598          UISupport.showErrorMessage( messages.get( "FailedToCloseProject.Error", name ) + e.getMessage() );
599          SoapUI.logError( e );
600       }
601    }
602 
603    public List<Project> getOpenProjectList()
604    {
605       List<Project> availableProjects = new ArrayList<Project>();
606 
607       for( Project project : projectList )
608          if( project.isOpen() )
609             availableProjects.add( project );
610 
611       return availableProjects;
612    }
613 
614    public Project openProject( Project project ) throws SoapUIException
615    {
616       return reloadProject( project );
617    }
618 
619    public String getId()
620    {
621       return String.valueOf( hashCode() );
622    }
623 
624    public List<? extends ModelItem> getChildren()
625    {
626       return getProjectList();
627    }
628 
629    public ModelItem getParent()
630    {
631       return null;
632    }
633 
634    public void inspectProjects()
635    {
636       for( int cnt = 0; cnt < projectList.size(); cnt++ )
637       {
638          Project project = projectList.get( cnt );
639          if( project.isOpen() )
640             project.inspect();
641       }
642    }
643 
644    public String getProjectPassword( String name )
645    {
646       return projectOptions.get( name );
647    }
648 
649    public void clearProjectPassword( String name )
650    {
651       projectOptions.remove( name );
652    }
653 
654 }