Coverage Report - org.argouml.persistence.PersistenceManager
 
Classes in this File Line Coverage Branch Coverage Complexity
MultitypeFileFilter
94%
16/17
87%
7/8
2.214
PersistenceManager
52%
57/109
40%
16/40
2.214
 
 1  
 /* $Id: PersistenceManager.java 17832 2010-01-12 19:02:29Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    bobtarling
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2004-2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.persistence;
 40  
 
 41  
 import java.awt.Component;
 42  
 import java.io.ByteArrayOutputStream;
 43  
 import java.io.File;
 44  
 import java.io.PrintStream;
 45  
 import java.io.UnsupportedEncodingException;
 46  
 import java.net.URI;
 47  
 import java.net.URISyntaxException;
 48  
 import java.util.ArrayList;
 49  
 import java.util.Collection;
 50  
 import java.util.Iterator;
 51  
 import java.util.List;
 52  
 
 53  
 import javax.swing.JFileChooser;
 54  
 import javax.swing.JOptionPane;
 55  
 import javax.swing.filechooser.FileFilter;
 56  
 
 57  
 import org.argouml.application.api.Argo;
 58  
 import org.argouml.configuration.Configuration;
 59  
 import org.argouml.configuration.ConfigurationKey;
 60  
 import org.argouml.i18n.Translator;
 61  
 import org.argouml.kernel.Project;
 62  
 import org.tigris.gef.util.UnexpectedException;
 63  
 
 64  
 
 65  
 /**
 66  
  * This class shall be the only one that knows in which file formats
 67  
  * ArgoUML is able to save and load. And all that knowledge is
 68  
  * concentrated in the constructor... <p>
 69  
  *
 70  
  * The PersisterManager manages the list of persisters. <p>
 71  
  *
 72  
  * This class is a singleton, since this allows external modules to
 73  
  * add extra persisters to the ArgoUML application.
 74  
  *
 75  
  * @author mvw@tigris.org
 76  
  */
 77  
 public final class PersistenceManager {
 78  
     /**
 79  
      * The singleton instance.
 80  
      */
 81  900
     private static final PersistenceManager INSTANCE =
 82  
         new PersistenceManager();
 83  
 
 84  
     private AbstractFilePersister defaultPersister;
 85  900
     private List<AbstractFilePersister> otherPersisters = 
 86  
         new ArrayList<AbstractFilePersister>();
 87  
     private UmlFilePersister quickViewDump;
 88  
     private XmiFilePersister xmiPersister;
 89  
     private XmiFilePersister xmlPersister;
 90  
     private UmlFilePersister umlPersister;
 91  
     private ZipFilePersister zipPersister;
 92  
 
 93  
     private AbstractFilePersister savePersister;
 94  
     
 95  
     /**
 96  
      * The configuration key for the project file location.
 97  
      */
 98  900
     public static final ConfigurationKey KEY_PROJECT_NAME_PATH =
 99  
         Configuration.makeKey("project", "name", "path");
 100  
 
 101  
     /**
 102  
      * The configuration key for the "open project" file location.
 103  
      */
 104  900
     public static final ConfigurationKey KEY_OPEN_PROJECT_PATH =
 105  
         Configuration.makeKey("project", "open", "path");
 106  
 
 107  
     /**
 108  
      * The configuration key for the "import xmi" file location.
 109  
      */
 110  900
     public static final ConfigurationKey KEY_IMPORT_XMI_PATH =
 111  
         Configuration.makeKey("xmi", "import", "path");
 112  
 
 113  
     /**
 114  
      * Create the default diagram persister.
 115  
      */
 116  900
     private DiagramMemberFilePersister diagramMemberFilePersister
 117  
         = new DiagramMemberFilePersister();
 118  
 
 119  
     /**
 120  
      * @return returns the singleton
 121  
      */
 122  
     public static PersistenceManager getInstance() {
 123  10616
         return INSTANCE;
 124  
     }
 125  
 
 126  
     /**
 127  
      * The constructor.
 128  
      */
 129  900
     private PersistenceManager() {
 130  
         // These are the file formats I know about:
 131  900
         defaultPersister = new OldZargoFilePersister();
 132  900
         quickViewDump = new UmlFilePersister();
 133  900
         xmiPersister = new XmiFilePersister();
 134  900
         otherPersisters.add(xmiPersister);
 135  900
         xmlPersister = new XmlFilePersister();
 136  900
         otherPersisters.add(xmlPersister);
 137  900
         umlPersister = new UmlFilePersister();
 138  900
         otherPersisters.add(umlPersister);
 139  900
         zipPersister = new ZipFilePersister();
 140  900
         otherPersisters.add(zipPersister);
 141  900
     }
 142  
 
 143  
     /**
 144  
      * This function allows to add new persisters. This can be done e.g.
 145  
      * by plugins/modules.
 146  
      *
 147  
      * @param fp the persister
 148  
      */
 149  
     public void register(AbstractFilePersister fp) {
 150  0
         otherPersisters.add(fp);
 151  0
     }
 152  
 
 153  
     /**
 154  
      * @param name the filename
 155  
      * @return the persister
 156  
      */
 157  
     public AbstractFilePersister getPersisterFromFileName(String name) {
 158  9633
         if (defaultPersister.isFileExtensionApplicable(name)) {
 159  0
             return defaultPersister;
 160  
         }
 161  9633
         for (AbstractFilePersister persister : otherPersisters) {
 162  38532
             if (persister.isFileExtensionApplicable(name)) {
 163  0
                 return persister;
 164  
             }
 165  
         }
 166  9633
         return null;
 167  
     }
 168  
 
 169  
     /**
 170  
      * @param chooser the filechooser of which the filters will be set
 171  
      * @param fileName the filename of the file to be saved (optional)
 172  
      */
 173  
     public void setSaveFileChooserFilters(JFileChooser chooser, 
 174  
             String fileName) {
 175  
         
 176  5
         chooser.addChoosableFileFilter(defaultPersister);
 177  5
         AbstractFilePersister defaultFileFilter = defaultPersister;
 178  
         
 179  5
         for (AbstractFilePersister fp : otherPersisters) {
 180  20
             if (fp.isSaveEnabled()
 181  
                     && !fp.equals(xmiPersister)
 182  
                     && !fp.equals(xmlPersister)) {
 183  10
                 chooser.addChoosableFileFilter(fp);
 184  10
                 if (fileName != null 
 185  
                         && fp.isFileExtensionApplicable(fileName)) {
 186  0
                     defaultFileFilter = fp;
 187  
                 }
 188  
             }
 189  
         }
 190  5
         chooser.setFileFilter(defaultFileFilter);
 191  5
     }
 192  
 
 193  
     /**
 194  
      * @param chooser the filechooser of which the filters will be set
 195  
      */
 196  
     public void setOpenFileChooserFilter(JFileChooser chooser) {
 197  37
         MultitypeFileFilter mf = new MultitypeFileFilter();
 198  37
         mf.add(defaultPersister);
 199  37
         chooser.addChoosableFileFilter(mf);
 200  37
         chooser.addChoosableFileFilter(defaultPersister);
 201  37
         Iterator iter = otherPersisters.iterator();
 202  185
         while (iter.hasNext()) {
 203  148
             AbstractFilePersister ff = (AbstractFilePersister) iter.next();
 204  148
             if (ff.isLoadEnabled()) {
 205  148
                 mf.add(ff);
 206  148
                 chooser.addChoosableFileFilter(ff);
 207  
             }
 208  148
         }
 209  37
         chooser.setFileFilter(mf);
 210  37
     }
 211  
 
 212  
     /**
 213  
      * @param chooser the filechooser of which the filters will be set
 214  
      */
 215  
     public void setXmiFileChooserFilter(JFileChooser chooser) {
 216  36
         chooser.addChoosableFileFilter(xmiPersister);
 217  36
         chooser.setFileFilter(xmiPersister);
 218  36
     }
 219  
 
 220  
     /**
 221  
      * @return the extension of the default persister
 222  
      *         (just the text, not the ".")
 223  
      */
 224  
     public String getDefaultExtension() {
 225  0
         return defaultPersister.getExtension();
 226  
     }
 227  
 
 228  
     /**
 229  
      * @return the extension of the xmi persister
 230  
      *         (just the text, not the ".")
 231  
      */
 232  
     public String getXmiExtension() {
 233  0
         return xmiPersister.getExtension();
 234  
     }
 235  
 
 236  
     /**
 237  
      * @param in the input file or path name which may or may not
 238  
      *           have a recognised extension
 239  
      * @return the amended file or pathname, guaranteed to have
 240  
      *         a recognised extension
 241  
      */
 242  
     public String fixExtension(String in) {
 243  0
         if (getPersisterFromFileName(in) == null) {
 244  0
             in += "." + getDefaultExtension();
 245  
         }
 246  0
         return in;
 247  
     }
 248  
 
 249  
     /**
 250  
      * @param in the input file or path name which may or may not
 251  
      *           have a "xmi" extension
 252  
      * @return the amended file or pathname, guaranteed to have
 253  
      *         a "xmi" extension
 254  
      */
 255  
     public String fixXmiExtension(String in) {
 256  0
         if (getPersisterFromFileName(in) != xmiPersister) {
 257  0
             in += "." + getXmiExtension();
 258  
         }
 259  0
         return in;
 260  
     }
 261  
 
 262  
 
 263  
     /**
 264  
      * @param in the input uri which may or may not have a recognised extension
 265  
      * @return the uri with default extension added,
 266  
      *         if it did not have a valid extension yet
 267  
      */
 268  
     public URI fixUriExtension(URI in) {
 269  
         URI newUri;
 270  0
         String n = in.toString();
 271  0
         n = fixExtension(n);
 272  
         try {
 273  0
             newUri = new URI(n);
 274  0
         } catch (java.net.URISyntaxException e) {
 275  0
             throw new UnexpectedException(e);
 276  0
         }
 277  0
         return newUri;
 278  
     }
 279  
 
 280  
     /**
 281  
      * Find the base name of the given filename.<p>
 282  
      *
 283  
      * This is the name minus any valid file extension.
 284  
      * Invalid extensions are left alone.
 285  
      *
 286  
      * @param n the given file name
 287  
      * @return the name (a String) without extension
 288  
      */
 289  
     public String getBaseName(String n) {
 290  8864
         AbstractFilePersister p = getPersisterFromFileName(n);
 291  8864
         if (p == null) {
 292  8864
             return n;
 293  
         }
 294  0
         int extLength = p.getExtension().length() + 1;
 295  0
         return n.substring(0, n.length() - extLength);
 296  
     }
 297  
 
 298  
     /**
 299  
      * @param p the project
 300  
      * @return the basename of the project
 301  
      */
 302  
     public String getProjectBaseName(Project p) {
 303  8864
         URI uri = p.getUri();
 304  8864
         String name = Translator.localize("label.projectbrowser-title");
 305  8864
         if (uri != null) {
 306  0
             name = new File(uri).getName();
 307  
         }
 308  8864
         return getBaseName(name);
 309  
     }
 310  
 
 311  
     /**
 312  
      * @param n the new project name
 313  
      * @param p the project that receives the name
 314  
      * @throws URISyntaxException if the URI is malformed
 315  
      */
 316  
     public void setProjectName(final String n, Project p)
 317  
         throws URISyntaxException {
 318  0
         String s = "";
 319  0
         if (p.getURI() != null) {
 320  0
             s = p.getURI().toString();
 321  
         }
 322  0
         s = s.substring(0, s.lastIndexOf("/") + 1) + n;
 323  0
         setProjectURI(new URI(s), p);
 324  0
     }
 325  
 
 326  
     /**
 327  
      * @param theUri the URI for the project
 328  
      * @param p the project that receives the URI
 329  
      */
 330  
     public void setProjectURI(URI theUri, Project p) {
 331  0
         if (theUri != null) {
 332  0
             theUri = fixUriExtension(theUri);
 333  
         }
 334  0
         p.setUri(theUri);
 335  0
     }
 336  
 
 337  
     /**
 338  
      * Generates a String dump of the current model for quick viewing.
 339  
      *
 340  
      * @param project The project to generate.
 341  
      * @return The whole model in a String.
 342  
      */
 343  
     public String getQuickViewDump(Project project) {
 344  0
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
 345  
         try {
 346  0
             quickViewDump.writeProject(project, stream, null);
 347  0
         } catch (Exception e) {
 348  
             // If anything goes wrong return the stack
 349  
             // trace as a string so that we get some
 350  
             // useful feedback.
 351  0
             e.printStackTrace(new PrintStream(stream));
 352  0
         }
 353  
         try {
 354  0
             return stream.toString(Argo.getEncoding());
 355  0
         } catch (UnsupportedEncodingException e) {
 356  0
             return e.toString();
 357  
         }
 358  
     }
 359  
 
 360  
     /**
 361  
      * Get the file persister for diagrams.
 362  
      *
 363  
      * @return the diagram file persister.
 364  
      */
 365  
     DiagramMemberFilePersister getDiagramMemberFilePersister() {
 366  9900
             return diagramMemberFilePersister;
 367  
     }
 368  
 
 369  
     /**
 370  
      * Set an alternative file persister for diagrams.
 371  
      *
 372  
      * @param persister the persister to use instead of the default
 373  
      */
 374  
     public void setDiagramMemberFilePersister(
 375  
             DiagramMemberFilePersister persister) {
 376  0
             diagramMemberFilePersister = persister;
 377  0
     }
 378  
 
 379  
     /**
 380  
      * Returns true if we are allowed to overwrite the given file.
 381  
      *
 382  
      * @param overwrite if true, then the user is not asked
 383  
      * @param file the given file
 384  
      * @return true if we are allowed to overwrite the given file
 385  
      * @param frame the Component to display the confirmation dialog on
 386  
      */
 387  
     public boolean confirmOverwrite(Component frame, 
 388  
             boolean overwrite, File file) {
 389  0
         if (file.exists() && !overwrite) {
 390  0
             String sConfirm =
 391  
                 Translator.messageFormat(
 392  
                     "optionpane.confirm-overwrite",
 393  
                     new Object[] {file});
 394  0
             int nResult =
 395  
                 JOptionPane.showConfirmDialog(
 396  
                         frame,
 397  
                         sConfirm,
 398  
                         Translator.localize(
 399  
                             "optionpane.confirm-overwrite-title"),
 400  
                         JOptionPane.YES_NO_OPTION,
 401  
                         JOptionPane.QUESTION_MESSAGE);
 402  0
             if (nResult != JOptionPane.YES_OPTION) {
 403  0
                 return false;
 404  
             }
 405  
         }
 406  0
         return true;
 407  
     }
 408  
 
 409  
 
 410  
     /**
 411  
      * Sets the currently used persister for saving.
 412  
      * 
 413  
      * @param persister the persister
 414  
      */
 415  
     public void setSavePersister(AbstractFilePersister persister) {
 416  0
         savePersister = persister;
 417  0
     }
 418  
     
 419  
     /**
 420  
      * Gets the currently used persister for saving.
 421  
      * 
 422  
      * @return the persister or null
 423  
      */
 424  
     public AbstractFilePersister getSavePersister() {
 425  0
         return savePersister;
 426  
     }
 427  
     
 428  
     /**
 429  
      * Figs are stored by class name and recreated by reflection. If the class
 430  
      * name changes or moves this provides a simple way of translating from
 431  
      * class name at time of save to the current class name without need for
 432  
      * XSL.
 433  
      * @param originalClassName The class name that may be in the save file
 434  
      * @param newClassName The class name to use in preference
 435  
      */
 436  
     public void addTranslation(
 437  
             final String originalClassName,
 438  
             final String newClassName) {
 439  9900
         getDiagramMemberFilePersister().addTranslation(
 440  
                 originalClassName,
 441  
                 newClassName);
 442  9900
     }
 443  
     
 444  
 }
 445  
 
 446  
 /**
 447  
  * Composite file filter which will accept any
 448  
  * file type added to it.
 449  
  */
 450  
 class MultitypeFileFilter extends FileFilter {
 451  
     private ArrayList<FileFilter> filters;
 452  
     private ArrayList<String> extensions;
 453  
     private String desc;
 454  
 
 455  
     /**
 456  
      * Constructor
 457  
      */
 458  
     public MultitypeFileFilter() {
 459  37
         super();
 460  37
         filters = new ArrayList<FileFilter>();
 461  37
         extensions = new ArrayList<String>();
 462  37
     }
 463  
 
 464  
     /**
 465  
      * Add a FileFilter to list of file filters to be accepted
 466  
      * 
 467  
      * @param filter FileFilter to be added
 468  
      */
 469  
     public void add(AbstractFilePersister filter) {
 470  185
         filters.add(filter);
 471  185
         String extension = filter.getExtension();
 472  185
         if (!extensions.contains(extension)) {
 473  185
             extensions.add(filter.getExtension());
 474  185
             desc =
 475  
                 ((desc == null)
 476  
                     ? ""
 477  
                     : desc + ", ")
 478  
                 + "*." + extension;
 479  
         }
 480  185
     }
 481  
 
 482  
     /**
 483  
      * Return all added FileFilters.
 484  
      * 
 485  
      * @return collection of FileFilters
 486  
      */
 487  
     public Collection<FileFilter> getAll() {
 488  0
         return filters;
 489  
     }
 490  
 
 491  
     /**
 492  
      * Accept any file that any of our filters will accept.
 493  
      *
 494  
      * {@inheritDoc}
 495  
      */
 496  
     @Override
 497  
     public boolean accept(File arg0) {
 498  286
         for (FileFilter ff : filters) {
 499  686
             if (ff.accept(arg0)) {
 500  183
                 return true;
 501  
             }
 502  
         }
 503  103
         return false;
 504  
     }
 505  
 
 506  
     /*
 507  
      * @see javax.swing.filechooser.FileFilter#getDescription()
 508  
      */
 509  
     @Override
 510  
     public String getDescription() {
 511  345
         Object[] s = {desc};
 512  345
         return Translator.messageFormat("filechooser.all-types-desc", s);
 513  
     }
 514  
 }