Coverage Report - org.argouml.persistence.ModelMemberFilePersister
 
Classes in this File Line Coverage Branch Coverage Complexity
ModelMemberFilePersister
0%
0/119
0%
0/44
3.643
 
 1  
 /* $Id: ModelMemberFilePersister.java 18968 2011-01-13 14:39:23Z tfmorris $
 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  
  *    thn
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2009 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.io.IOException;
 42  
 import java.io.InputStream;
 43  
 import java.io.OutputStream;
 44  
 import java.net.URL;
 45  
 import java.util.ArrayList;
 46  
 import java.util.Collection;
 47  
 import java.util.HashMap;
 48  
 import java.util.Iterator;
 49  
 import java.util.List;
 50  
 
 51  
 import org.apache.log4j.Logger;
 52  
 import org.argouml.application.api.Argo;
 53  
 import org.argouml.application.helpers.ApplicationVersion;
 54  
 import org.argouml.configuration.Configuration;
 55  
 import org.argouml.kernel.Project;
 56  
 import org.argouml.kernel.ProjectMember;
 57  
 import org.argouml.model.Facade;
 58  
 import org.argouml.model.Model;
 59  
 import org.argouml.model.UmlException;
 60  
 import org.argouml.model.XmiException;
 61  
 import org.argouml.model.XmiReader;
 62  
 import org.argouml.model.XmiWriter;
 63  
 import org.argouml.uml.ProjectMemberModel;
 64  
 import org.argouml.uml.diagram.ArgoDiagram;
 65  
 import org.argouml.uml.diagram.DiagramFactory;
 66  
 import org.argouml.uml.diagram.DiagramFactory.DiagramType;
 67  
 import org.xml.sax.InputSource;
 68  
 
 69  
 /**
 70  
  * The file persister for the UML model.
 71  
  * @author Bob Tarling
 72  
  */
 73  0
 class ModelMemberFilePersister extends MemberFilePersister 
 74  
     implements XmiExtensionParser {
 75  
 
 76  0
     private static final Logger LOG =
 77  
         Logger.getLogger(ModelMemberFilePersister.class);
 78  
 
 79  
     private Object curModel;
 80  
     private HashMap<String, Object> uUIDRefs;
 81  
 
 82  
     private Collection elementsRead;
 83  
     
 84  
     /**
 85  
      * Loads a model (XMI only) from a URL. BE ADVISED this
 86  
      * method has a side effect. It sets _UUIDREFS to the model.<p>
 87  
      *
 88  
      * If there is a problem with the xmi file, an error is set in the
 89  
      * getLastLoadStatus() field. This needs to be examined by the
 90  
      * calling function.<p>
 91  
      */
 92  
     public void load(Project project, URL url)
 93  
         throws OpenException {
 94  
         
 95  0
         load(project, new InputSource(url.toExternalForm()));
 96  0
     }
 97  
     
 98  
     /**
 99  
      * Loads a model (XMI only) from an input stream. BE ADVISED this
 100  
      * method has a side effect. It sets _UUIDREFS to the model.<p>
 101  
      *
 102  
      * If there is a problem with the xmi file, an error is set in the
 103  
      * getLastLoadStatus() field. This needs to be examined by the
 104  
      * calling function.<p>
 105  
      *
 106  
      * @see org.argouml.persistence.MemberFilePersister#load(org.argouml.kernel.Project,
 107  
      * java.io.InputStream)
 108  
      */
 109  
     public void load(Project project, InputStream inputStream)
 110  
         throws OpenException {
 111  
         
 112  0
         load(project, new InputSource(inputStream));
 113  0
     }
 114  
 
 115  
 
 116  
     public void load(Project project, InputSource source)
 117  
         throws OpenException {
 118  
 
 119  0
         Object mmodel = null;
 120  
 
 121  
         // 2002-07-18
 122  
         // Jaap Branderhorst
 123  
         // changed the loading of the projectfiles to solve hanging
 124  
         // of argouml if a project is corrupted. Issue 913
 125  
         // Created xmireader with method getErrors to check if parsing went well
 126  
         try {
 127  0
             source.setEncoding(Argo.getEncoding());
 128  0
             readModels(source);
 129  0
             mmodel = getCurModel();
 130  0
         } catch (OpenException e) {
 131  0
             LOG.error("UmlException caught", e);
 132  0
             throw e;
 133  0
         }
 134  
         // This should probably be inside xmiReader.parse
 135  
         // but there is another place in this source
 136  
         // where XMIReader is used, but it appears to be
 137  
         // the NSUML XMIReader.  When Argo XMIReader is used
 138  
         // consistently, it can be responsible for loading
 139  
         // the listener.  Until then, do it here.
 140  0
         Model.getUmlHelper().addListenersToModel(mmodel);
 141  
 
 142  
         // TODO Add all top level packages
 143  0
         project.addMember(mmodel);
 144  
 
 145  0
         project.setUUIDRefs(new HashMap<String, Object>(getUUIDRefs()));
 146  0
     }
 147  
 
 148  
     /*
 149  
      * @see org.argouml.persistence.MemberFilePersister#getMainTag()
 150  
      */
 151  
     public String getMainTag() {
 152  
         try {
 153  0
             return Model.getXmiReader().getTagName();
 154  0
         } catch (UmlException e) {
 155  
             // Should never happen - something's really wrong
 156  0
             throw new RuntimeException(e);
 157  
         }
 158  
     }
 159  
 
 160  
     /**
 161  
      * Save the project model to XMI.
 162  
      * 
 163  
      * @see org.argouml.persistence.MemberFilePersister#save(ProjectMember, OutputStream)
 164  
      */
 165  
     public void save(ProjectMember member, OutputStream outStream)
 166  
         throws SaveException {
 167  
 
 168  0
         ProjectMemberModel pmm = (ProjectMemberModel) member;
 169  0
         Object model = pmm.getModel();
 170  
 
 171  
         try {
 172  0
             XmiWriter xmiWriter = 
 173  
                 Model.getXmiWriter(model, outStream, 
 174  
                         ApplicationVersion.getVersion() + "(" 
 175  
                         + UmlFilePersister.PERSISTENCE_VERSION + ")");
 176  
 
 177  0
             xmiWriter.write();
 178  0
             outStream.flush();
 179  0
         } catch (UmlException e) {
 180  0
             throw new SaveException(e);
 181  0
         } catch (IOException e) {
 182  0
             throw new SaveException(e);
 183  0
         }
 184  
 
 185  0
     }
 186  
     
 187  
     public void parse(String label, String xmiExtensionString) {
 188  0
         LOG.info("Parsing an extension for " + label);
 189  0
     }
 190  
 
 191  
 
 192  
     /**
 193  
      * @return the current model
 194  
      * @deprecated by tfmorris for 0.33.1
 195  
      */
 196  
     @Deprecated
 197  
     public Object getCurModel() {
 198  0
         return curModel;
 199  
     }
 200  
 
 201  
     /**
 202  
      * Return XMI id to object map for the most recently read XMI file.
 203  
      * 
 204  
      * @return the UUID
 205  
      */
 206  
     public HashMap<String, Object> getUUIDRefs() {
 207  0
         return uUIDRefs;
 208  
     }
 209  
 
 210  
     ////////////////////////////////////////////////////////////////
 211  
     // main parsing methods
 212  
 
 213  
     /**
 214  
      * Read an XMI file from the given URL.
 215  
      *
 216  
      * @param url the URL
 217  
      * @param xmiExtensionParser the XmiExtensionParser
 218  
      * @throws OpenException when there is an IO error
 219  
      */
 220  
     public synchronized void readModels(URL url,
 221  
             XmiExtensionParser xmiExtensionParser) throws OpenException {
 222  0
         LOG.info("=======================================");
 223  0
         LOG.info("== READING MODEL " + url);
 224  
         try {
 225  
             // TODO: What progressMgr is to be used here? Where does
 226  
             //       it come from?
 227  0
             InputSource source =
 228  
                 new InputSource(new XmiInputStream(
 229  
                     url.openStream(), xmiExtensionParser, 100000, null));
 230  
             
 231  0
             source.setSystemId(url.toString());
 232  0
             readModels(source);
 233  0
         } catch (IOException ex) {
 234  0
             throw new OpenException(ex);
 235  0
         }
 236  0
     }
 237  
 
 238  
     /**
 239  
      * Read a XMI file from the given inputsource.
 240  
      * 
 241  
      * @param source The InputSource. The systemId of the input source should be
 242  
      *                set so that it can be used to resolve external references.
 243  
      * @throws OpenException If an error occur while reading the source
 244  
      */
 245  
     public synchronized void readModels(InputSource source)
 246  
         throws OpenException {
 247  
 
 248  0
         XmiReader reader = null;
 249  
         try {
 250  0
             reader = Model.getXmiReader();
 251  
             
 252  0
             if (Configuration.getBoolean(Argo.KEY_XMI_STRIP_DIAGRAMS, false)) {
 253  
                 // TODO: Not implemented by eUML
 254  0
                 reader.setIgnoredElements(new String[] {"UML:Diagram"});
 255  
             } else {
 256  0
                 reader.setIgnoredElements(null);
 257  
             }
 258  
 
 259  0
             List<String> searchPath = reader.getSearchPath();
 260  0
             String pathList = 
 261  
                 System.getProperty("org.argouml.model.modules_search_path");
 262  0
             if (pathList != null) {
 263  0
                 String[] paths = pathList.split(",");
 264  0
                 for (String path : paths) {
 265  0
                     if (!searchPath.contains(path)) {
 266  0
                         reader.addSearchPath(path);
 267  
                     }
 268  
                 }
 269  
             }
 270  0
             reader.addSearchPath(source.getSystemId());
 271  
             
 272  0
             curModel = null;
 273  0
             elementsRead = reader.parse(source, false);
 274  0
             if (elementsRead != null && !elementsRead.isEmpty()) {
 275  0
                 Facade facade = Model.getFacade();
 276  
                 Object current;
 277  0
                 Iterator elements = elementsRead.iterator();
 278  0
                 while (elements.hasNext()) {
 279  0
                     current = elements.next();
 280  0
                     if (facade.isAModel(current)) {
 281  0
                         LOG.info("Loaded model '" + facade.getName(current)
 282  
                                  + "'");
 283  0
                         if (curModel == null) {
 284  0
                             curModel = current;
 285  
                         }
 286  0
                     } else if (facade.isAProfile(current)) {
 287  0
                         LOG.info("Loaded profile '" + facade.getName(current)
 288  
                                  + "'");
 289  0
                         if (curModel == null) {
 290  0
                             curModel = current;
 291  
                         }
 292  
                     }
 293  
                     // TODO: add stereotype application (eCore AnyType?)
 294  
                 }
 295  
             }
 296  0
             uUIDRefs = 
 297  
                 new HashMap<String, Object>(reader.getXMIUUIDToObjectMap());
 298  0
         } catch (XmiException ex) {
 299  0
             throw new XmiFormatException(ex);
 300  0
         } catch (UmlException ex) {
 301  
             // Could this be some other type of internal error that we want
 302  
             // to handle differently?  Don't think so.  - tfm
 303  0
             throw new XmiFormatException(ex);
 304  0
         }
 305  0
         LOG.info("=======================================");
 306  0
     }
 307  
 
 308  
     /**
 309  
      * Create and register diagrams for activity and statemachines in the
 310  
      * model(s) of the project. If no other diagrams are created, a default
 311  
      * Class Diagram will be created. ArgoUML currently requires at least one
 312  
      * diagram for proper operation. 
 313  
      * 
 314  
      * TODO: Move to XmiFilePersister (protected)
 315  
      * 
 316  
      * @param project
 317  
      *            The project
 318  
      */
 319  
     public void registerDiagrams(Project project) {
 320  0
         registerDiagramsInternal(project, elementsRead, true);
 321  0
     }
 322  
     
 323  
 
 324  
     /**
 325  
      * Internal method create diagrams for activity graphs and state machines.
 326  
      * It exists soley to contain common functionality from the two public
 327  
      * methods.  It can be merged into its caller when the deprecated version
 328  
      * of the public method goes away.
 329  
      * 
 330  
      * @param project
 331  
      *            The project
 332  
      * @param elements
 333  
      *            Collection of top level model elements to process
 334  
      * @param atLeastOne
 335  
      *            If true, forces at least one diagram to be created.
 336  
      */
 337  
     private void registerDiagramsInternal(Project project, Collection elements,
 338  
             boolean atLeastOne) {
 339  0
         Facade facade = Model.getFacade();
 340  0
         Collection diagramsElement = new ArrayList();
 341  0
         Iterator it = elements.iterator();
 342  0
         while (it.hasNext()) {
 343  0
             Object element = it.next();
 344  0
             if (facade.isAModel(element)) {
 345  0
                 diagramsElement.addAll(Model.getModelManagementHelper()
 346  
                         .getAllModelElementsOfKind(element,
 347  
                                 Model.getMetaTypes().getStateMachine()));
 348  0
             } else if (facade.isAStateMachine(element)) {
 349  0
                 diagramsElement.add(element);
 350  
             }
 351  0
         }
 352  0
         DiagramFactory diagramFactory = DiagramFactory.getInstance();
 353  0
         it = diagramsElement.iterator();
 354  0
         while (it.hasNext()) {
 355  0
             Object statemachine = it.next();
 356  0
             Object namespace = facade.getNamespace(statemachine);
 357  0
             if (namespace == null) {
 358  0
                 namespace = facade.getContext(statemachine);
 359  0
                 Model.getCoreHelper().setNamespace(statemachine, namespace);
 360  
             }
 361  
             
 362  0
             ArgoDiagram diagram = null;
 363  0
             if (facade.isAActivityGraph(statemachine)) {
 364  0
                 LOG.info("Creating activity diagram for "
 365  
                         + facade.getUMLClassName(statemachine)
 366  
                         + "<<" + facade.getName(statemachine) + ">>");
 367  0
                 diagram = diagramFactory.createDiagram(
 368  
                         DiagramType.Activity,
 369  
                         namespace,
 370  
                         statemachine);
 371  
             } else {
 372  0
                 LOG.info("Creating state diagram for "
 373  
                         + facade.getUMLClassName(statemachine)
 374  
                         + "<<" + facade.getName(statemachine) + ">>");
 375  0
                 diagram = diagramFactory.createDiagram(
 376  
                         DiagramType.State,
 377  
                         namespace,
 378  
                         statemachine);
 379  
             }
 380  0
             if (diagram != null) {
 381  0
                 project.addMember(diagram);
 382  
             }
 383  
             
 384  0
         }
 385  
         // ISSUE 3516 : Make sure there is at least one diagram because
 386  
         // ArgoUML requires it for correct operation
 387  0
         if (atLeastOne && project.getDiagramCount() < 1) {
 388  0
             ArgoDiagram d = diagramFactory.createDiagram(
 389  
                     DiagramType.Class, curModel, null);
 390  0
             project.addMember(d);
 391  
         }
 392  0
         if (project.getDiagramCount() >= 1
 393  
                 && project.getActiveDiagram() == null) {
 394  0
             project.setActiveDiagram(
 395  
                     project.getDiagramList().get(0));
 396  
         }
 397  0
     }
 398  
 
 399  
     /**
 400  
      * @return Returns the elementsRead.
 401  
      */
 402  
     public Collection getElementsRead() {
 403  0
         return elementsRead;
 404  
     }
 405  
 
 406  
     /**
 407  
      * @param elements The elementsRead to set.
 408  
      */
 409  
     public void setElementsRead(Collection elements) {
 410  0
         this.elementsRead = elements;
 411  0
     }
 412  
 }