Coverage Report - org.argouml.persistence.ProfileConfigurationFilePersister
 
Classes in this File Line Coverage Branch Coverage Complexity
ProfileConfigurationFilePersister
0%
0/73
0%
0/18
2.76
ProfileConfigurationParser
0%
0/76
0%
0/32
2.76
ProfileConfigurationParser$ProfileConfigurationTokenTable
0%
0/9
N/A
2.76
 
 1  
 /* $Id: ProfileConfigurationFilePersister.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  
  *    tfmorris
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2007-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.File;
 42  
 import java.io.FileOutputStream;
 43  
 import java.io.IOException;
 44  
 import java.io.InputStream;
 45  
 import java.io.OutputStream;
 46  
 import java.io.OutputStreamWriter;
 47  
 import java.io.PrintWriter;
 48  
 import java.io.StringWriter;
 49  
 import java.io.UnsupportedEncodingException;
 50  
 import java.net.URL;
 51  
 import java.util.ArrayList;
 52  
 import java.util.Collection;
 53  
 import java.util.List;
 54  
 
 55  
 import org.apache.log4j.Logger;
 56  
 import org.argouml.application.api.Argo;
 57  
 import org.argouml.application.helpers.ApplicationVersion;
 58  
 import org.argouml.configuration.Configuration;
 59  
 import org.argouml.kernel.ProfileConfiguration;
 60  
 import org.argouml.kernel.Project;
 61  
 import org.argouml.kernel.ProjectMember;
 62  
 import org.argouml.model.Model;
 63  
 import org.argouml.model.UmlException;
 64  
 import org.argouml.model.XmiWriter;
 65  
 import org.argouml.profile.Profile;
 66  
 import org.argouml.profile.ProfileFacade;
 67  
 import org.argouml.profile.ProfileManager;
 68  
 import org.argouml.profile.UserDefinedProfile;
 69  
 import org.xml.sax.InputSource;
 70  
 import org.xml.sax.SAXException;
 71  
 
 72  
 /**
 73  
  * Persister for project's profile configuration.
 74  
  *
 75  
  * @author maurelio1234
 76  
  */
 77  0
 public class ProfileConfigurationFilePersister extends MemberFilePersister {
 78  
     
 79  0
     private static final Logger LOG = 
 80  
         Logger.getLogger(ProfileConfigurationFilePersister.class);
 81  
 
 82  
     /*
 83  
      * @see org.argouml.persistence.MemberFilePersister#getMainTag()
 84  
      */
 85  
     public String getMainTag() {
 86  0
         return "profile";
 87  
     }
 88  
 
 89  
     public void load(Project project, InputStream inputStream)
 90  
         throws OpenException {
 91  0
         load(project, new InputSource(inputStream));
 92  0
     }
 93  
     
 94  
     /*
 95  
      * @see org.argouml.persistence.MemberFilePersister#load(org.argouml.kernel.Project, java.io.InputStream)
 96  
      */
 97  
     public void load(Project project, InputSource inputSource)
 98  
         throws OpenException {
 99  
         try {
 100  0
             ProfileConfigurationParser parser = 
 101  
                 new ProfileConfigurationParser();
 102  0
             parser.parse(inputSource);
 103  0
             Collection<Profile> profiles = parser.getProfiles();
 104  
 
 105  0
             Collection<String> unresolved = parser.getUnresolvedFilenames();
 106  0
             if (!unresolved.isEmpty()) {
 107  0
                 profiles.addAll(loadUnresolved(unresolved));
 108  
             }
 109  
 
 110  0
             ProfileConfiguration pc = new ProfileConfiguration(project, 
 111  
                     profiles);
 112  0
             project.setProfileConfiguration(pc);
 113  0
         } catch (Exception e) {
 114  0
             if (e instanceof OpenException) {
 115  0
                 throw (OpenException) e;
 116  
             }
 117  0
             throw new OpenException(e);
 118  0
         }
 119  0
     }
 120  
 
 121  
 
 122  
     /**
 123  
      * Use XMI as a fall back alternative when the file for the user defined
 124  
      * profile isn't found by the profile manager.
 125  
      * <p>
 126  
      * TODO: work in progress, see issue 5039
 127  
      * 
 128  
      * @param unresolved collection of unresolved filenames from the parser
 129  
      * @return collection of resolved profiles
 130  
      */
 131  
     private Collection<Profile> loadUnresolved(Collection<String> unresolved) {
 132  0
         Collection<Profile> profiles = new ArrayList<Profile>();        
 133  0
         ProfileManager profileManager = ProfileFacade.getManager();
 134  0
         for (String filename : unresolved) {
 135  
             // TODO: work in progress, see issue 5039
 136  
 //            addUserDefinedProfile(filename, xmi, profileManager);
 137  
 //            Profile profile = getMatchingUserDefinedProfile(filename,
 138  
 //                    profileManager);
 139  
 //            assert profile != null : "Profile should have been found now.";
 140  
 //            profiles.add(profile);
 141  
         }
 142  0
         return profiles;
 143  
     }
 144  
 
 145  
     /**
 146  
      * Register a user defined profile in the profileManager, using the backup 
 147  
      * XMI file from the project being loaded.
 148  
      * <p>
 149  
      * <em>NOTE:</em> This has the side effect of permanently registering the
 150  
      * profile which may not be what the user wants.
 151  
      * 
 152  
      * @param fileName name of original XMI file that the author of the project
 153  
      *                used when creating the UserDefinedProfile.
 154  
      * @param xmi the contents of the XMI file.
 155  
      * @param profileManager the {@link ProfileManager}.
 156  
      * @throws IOException on any i/o error
 157  
      */
 158  
     private void addUserDefinedProfile(String fileName, StringBuffer xmi,
 159  
             ProfileManager profileManager) throws IOException {
 160  0
         File profilesDirectory = getProfilesDirectory(profileManager);
 161  0
         File profileFile = new File(profilesDirectory, fileName);
 162  0
         OutputStreamWriter writer = new OutputStreamWriter(
 163  
                 new FileOutputStream(profileFile), 
 164  
                 Argo.getEncoding());
 165  0
         writer.write(xmi.toString());
 166  0
         writer.close();
 167  0
         LOG.info("Wrote user defined profile \"" + profileFile 
 168  
             + "\", with size " + xmi.length() + ".");
 169  0
         if (isSomeProfileDirectoryConfigured(profileManager)) {
 170  0
             profileManager.refreshRegisteredProfiles();
 171  
         } else {
 172  0
             profileManager.addSearchPathDirectory(
 173  
                 profilesDirectory.getAbsolutePath());
 174  
         }
 175  0
     }
 176  
 
 177  
 
 178  
     private static File getProfilesDirectory(ProfileManager profileManager) {
 179  0
         if (isSomeProfileDirectoryConfigured(profileManager)) {
 180  0
             List<String> directories = 
 181  
                 profileManager.getSearchPathDirectories();
 182  0
             return new File(directories.get(0));
 183  
         } else {
 184  0
             File userSettingsFile = new File(
 185  
                 Configuration.getFactory().getConfigurationHandler().
 186  
                     getDefaultPath());
 187  0
             return userSettingsFile.getParentFile();
 188  
         }
 189  
     }
 190  
 
 191  
     private static boolean isSomeProfileDirectoryConfigured(
 192  
             ProfileManager profileManager) {
 193  0
         return profileManager.getSearchPathDirectories().size() > 0;
 194  
     }
 195  
 
 196  
     /*
 197  
      * @see org.argouml.persistence.MemberFilePersister#save(org.argouml.kernel.ProjectMember, java.io.OutputStream)
 198  
      */
 199  
     public void save(ProjectMember member, OutputStream stream)
 200  
         throws SaveException {
 201  
         
 202  
         PrintWriter w;
 203  
         try {
 204  0
             w = new PrintWriter(new OutputStreamWriter(stream, "UTF-8"));
 205  0
         } catch (UnsupportedEncodingException e1) {
 206  0
             throw new SaveException("UTF-8 encoding not supported on platform",
 207  
                     e1);
 208  0
         }
 209  0
         saveProjectMember(member, w);
 210  0
         w.flush();
 211  0
     }
 212  
 
 213  
     private void saveProjectMember(ProjectMember member, PrintWriter w)
 214  
         throws SaveException {
 215  
         
 216  
         try {
 217  0
             if (member instanceof ProfileConfiguration) {
 218  0
                 ProfileConfiguration pc = (ProfileConfiguration) member;
 219  
 
 220  0
                 w.println("<?xml version = \"1.0\" encoding = \"UTF-8\" ?>");
 221  
                 // TODO: This DTD doesn't exist, so we can't tell readers to
 222  
                 // look for it
 223  
 //                w.println("<!DOCTYPE profile SYSTEM \"profile.dtd\" >");
 224  
                 // but we need a 2nd line to make the funky UML persister work
 225  0
                 w.println(""); // remove this line if the above is uncommented
 226  0
                 w.println("<profile>");
 227  
 
 228  0
                 for (Profile profile : pc.getProfiles()) {
 229  0
                     if (profile instanceof UserDefinedProfile) {
 230  0
                         UserDefinedProfile uprofile = 
 231  
                             (UserDefinedProfile) profile;
 232  0
                         w.println("\t\t<userDefined>");
 233  0
                         w.println("\t\t\t<filename>"
 234  
                                 + uprofile.getModelFile().getName()
 235  
                                 + "</filename>");
 236  0
                         w.println("\t\t\t<model>");
 237  
 
 238  0
                         printModelXMI(w, uprofile.getProfilePackages());
 239  
 
 240  0
                         w.println("\t\t\t</model>");
 241  0
                         w.println("\t\t</userDefined>");
 242  0
                     } else {
 243  0
                         w.println("\t\t<plugin>");
 244  0
                         w.println("\t\t\t" + profile.getProfileIdentifier());
 245  0
                         w.println("\t\t</plugin>");
 246  
                     }
 247  
                 }
 248  
 
 249  0
                 w.println("</profile>");
 250  
             }
 251  0
         } catch (Exception e) {
 252  0
             e.printStackTrace();
 253  0
             throw new SaveException(e);
 254  0
         }
 255  0
     }
 256  
 
 257  
     private void printModelXMI(PrintWriter w, Collection profileModels) 
 258  
         throws UmlException {
 259  
         
 260  
         // TODO: Why is this not executed?  Remove if not needed - tfm
 261  
         if (true) {
 262  0
             return;
 263  
         }
 264  
 
 265  
         StringWriter myWriter = new StringWriter();
 266  
         for (Object model : profileModels) {
 267  
             XmiWriter xmiWriter = Model.getXmiWriter(model, 
 268  
                 (OutputStream) null, //myWriter, 
 269  
                 ApplicationVersion.getVersion() + "("
 270  
                     + UmlFilePersister.PERSISTENCE_VERSION + ")");
 271  
             xmiWriter.write();
 272  
         }
 273  
 
 274  
         myWriter.flush();
 275  
         w.println("" + myWriter.toString());
 276  
     }
 277  
 
 278  
 
 279  
     @Override
 280  
     public void load(Project project, URL url) throws OpenException {
 281  0
         load(project, new InputSource(url.toExternalForm()));
 282  0
     }
 283  
     
 284  
 }
 285  
 
 286  
 /**
 287  
  * Parser for Profile Configuration.
 288  
  * 
 289  
  * @author Tom Morris <tfmorris@gmail.com>
 290  
  */
 291  
 class ProfileConfigurationParser extends SAXParserBase {
 292  
 
 293  0
     private static final Logger LOG = Logger
 294  
             .getLogger(ProfileConfigurationParser.class);
 295  
 
 296  0
     private ProfileConfigurationTokenTable tokens = 
 297  
         new ProfileConfigurationTokenTable();
 298  
 
 299  
     private Profile profile;
 300  
 
 301  
     private String model;
 302  
 
 303  
     private String filename;
 304  
 
 305  0
     private Collection<Profile> profiles = new ArrayList<Profile>();
 306  
 
 307  0
     private Collection<String> unresolvedFilenames = new ArrayList<String>();
 308  
 
 309  
     /**
 310  
      * Construct the parser.
 311  
      */
 312  0
     public ProfileConfigurationParser() {
 313  
         // Empty constructor
 314  0
     }
 315  
 
 316  
     public Collection<Profile> getProfiles() {
 317  0
         return profiles;
 318  
     }
 319  
 
 320  
     public Collection<String> getUnresolvedFilenames() {
 321  0
         return unresolvedFilenames;
 322  
     }
 323  
 
 324  
     public void handleStartElement(XMLElement e) {
 325  
 
 326  
         try {
 327  0
             switch (tokens.toToken(e.getName(), true)) {
 328  
 
 329  
             case ProfileConfigurationTokenTable.TOKEN_PROFILE:
 330  0
                 break;
 331  
             case ProfileConfigurationTokenTable.TOKEN_PLUGIN:
 332  0
                 profile = null;
 333  0
                 break;
 334  
             case ProfileConfigurationTokenTable.TOKEN_USER_DEFINED:
 335  0
                 profile = null;
 336  0
                 filename = null;
 337  0
                 model = null;
 338  0
                 break;
 339  
             case ProfileConfigurationTokenTable.TOKEN_FILENAME:
 340  0
                 break;
 341  
             case ProfileConfigurationTokenTable.TOKEN_MODEL:
 342  0
                 break;
 343  
 
 344  
             default:
 345  0
                 LOG.warn("WARNING: unknown tag:" + e.getName());
 346  
                 break;
 347  
             }
 348  0
         } catch (Exception ex) {
 349  0
             LOG.error("Exception in startelement", ex);
 350  0
         }
 351  0
     }
 352  
 
 353  
     /**
 354  
      * Called by the XML implementation to signal the end of an XML entity.
 355  
      * 
 356  
      * @param e The XML entity that ends.
 357  
      * @throws SAXException on any error
 358  
      */
 359  
     public void handleEndElement(XMLElement e) throws SAXException {
 360  
 
 361  
         try {
 362  0
             switch (tokens.toToken(e.getName(), false)) {
 363  
 
 364  
             case ProfileConfigurationTokenTable.TOKEN_PROFILE:
 365  0
                 handleProfileEnd(e);
 366  0
                 break;
 367  
             case ProfileConfigurationTokenTable.TOKEN_PLUGIN:
 368  0
                 handlePluginEnd(e);
 369  0
                 break;
 370  
             case ProfileConfigurationTokenTable.TOKEN_USER_DEFINED:
 371  0
                 handleUserDefinedEnd(e);
 372  0
                 break;
 373  
             case ProfileConfigurationTokenTable.TOKEN_FILENAME:
 374  0
                 handleFilenameEnd(e);
 375  0
                 break;
 376  
             case ProfileConfigurationTokenTable.TOKEN_MODEL:
 377  0
                 handleModelEnd(e);
 378  0
                 break;
 379  
 
 380  
             default:
 381  0
                 LOG.warn("WARNING: unknown end tag:" + e.getName());
 382  
                 break;
 383  
             }
 384  0
         } catch (Exception ex) {
 385  0
             throw new SAXException(ex);
 386  0
         }
 387  0
     }
 388  
 
 389  
     protected void handleProfileEnd(XMLElement e) {
 390  0
         if (profiles.isEmpty()) {
 391  0
             LOG.warn("No profiles defined");
 392  
         }
 393  0
     }
 394  
 
 395  
     protected void handlePluginEnd(XMLElement e) throws SAXException {
 396  0
         String name = e.getText().trim();
 397  0
         profile = lookupProfile(name);
 398  0
         if (profile != null) {
 399  0
             profiles.add(profile);
 400  0
             LOG.debug("Found plugin profile " + name);
 401  
         } else {
 402  0
             LOG.error("Unabled to find plugin profile - " + name);
 403  
         }
 404  0
     }
 405  
 
 406  
     private static Profile lookupProfile(String profileIdentifier)
 407  
         throws SAXException {
 408  
         Profile profile;
 409  0
         profile = ProfileFacade.getManager().lookForRegisteredProfile(
 410  
                 profileIdentifier);
 411  0
         if (profile == null) {
 412  
 
 413  
             // for compatibility with older format
 414  0
             profile = ProfileFacade.getManager().getProfileForClass(
 415  
                     profileIdentifier);
 416  
 
 417  0
             if (profile == null) {
 418  0
                 throw new SAXException("Plugin profile \"" + profileIdentifier
 419  
                         + "\" is not available in installation.", null);
 420  
             }
 421  
         }
 422  0
         return profile;
 423  
     }
 424  
 
 425  
     protected void handleUserDefinedEnd(XMLElement e) {
 426  
         // <model> is not used in current implementation
 427  0
         if (filename == null /* || model == null */) {
 428  0
             LOG.error("Got badly formed user defined profile entry " + e);
 429  
         }
 430  0
         profile = getMatchingUserDefinedProfile(filename, ProfileFacade
 431  
                 .getManager());
 432  
 
 433  0
         if (profile == null) {
 434  0
             unresolvedFilenames.add(filename);
 435  
         } else {
 436  0
             profiles.add(profile);
 437  0
             LOG.debug("Loaded user defined profile - filename = " + filename);
 438  
         }
 439  
 
 440  0
     }
 441  
 
 442  
     private static Profile getMatchingUserDefinedProfile(String fileName,
 443  
             ProfileManager profileManager) {
 444  
         for (Profile candidateProfile 
 445  0
                 : profileManager.getRegisteredProfiles()) {
 446  0
             if (candidateProfile instanceof UserDefinedProfile) {
 447  0
                 UserDefinedProfile userProfile = 
 448  
                     (UserDefinedProfile) candidateProfile;
 449  0
                 if (userProfile.getModelFile() != null
 450  
                         && fileName
 451  
                                 .equals(userProfile.getModelFile().getName())) {
 452  0
                     return userProfile;
 453  
                 }
 454  0
             }
 455  
         }
 456  0
         return null;
 457  
     }
 458  
 
 459  
     protected void handleFilenameEnd(XMLElement e) {
 460  0
         filename = e.getText().trim();
 461  0
         LOG.debug("Got filename = " + filename);
 462  0
     }
 463  
 
 464  
     protected void handleModelEnd(XMLElement e) {
 465  0
         model = e.getText().trim();
 466  0
         LOG.debug("Got model = " + model);
 467  0
     }
 468  
 
 469  
     /**
 470  
      * Token Table for Profile Configuration parser.
 471  
      * 
 472  
      * @author Tom Morris
 473  
      */
 474  
     class ProfileConfigurationTokenTable extends XMLTokenTableBase {
 475  
 
 476  
         private static final String STRING_PROFILE = "profile";
 477  
 
 478  
         private static final String STRING_PLUGIN = "plugin";
 479  
 
 480  
         private static final String STRING_USER_DEFINED = "userDefined";
 481  
 
 482  
         private static final String STRING_FILENAME = "filename";
 483  
 
 484  
         private static final String STRING_MODEL = "model";
 485  
 
 486  
         public static final int TOKEN_PROFILE = 1;
 487  
 
 488  
         public static final int TOKEN_PLUGIN = 2;
 489  
 
 490  
         public static final int TOKEN_USER_DEFINED = 3;
 491  
 
 492  
         public static final int TOKEN_FILENAME = 4;
 493  
 
 494  
         public static final int TOKEN_MODEL = 5;
 495  
 
 496  
         private static final int TOKEN_LAST = 5;
 497  
 
 498  
         public static final int TOKEN_UNDEFINED = 999;
 499  
 
 500  
         /**
 501  
          * Construct the token table.,
 502  
          */
 503  0
         public ProfileConfigurationTokenTable() {
 504  0
             super(TOKEN_LAST);
 505  0
         }
 506  
 
 507  
         protected void setupTokens() {
 508  0
             addToken(STRING_PROFILE, Integer.valueOf(TOKEN_PROFILE));
 509  0
             addToken(STRING_PLUGIN, Integer.valueOf(TOKEN_PLUGIN));
 510  0
             addToken(STRING_USER_DEFINED, Integer.valueOf(TOKEN_USER_DEFINED));
 511  0
             addToken(STRING_FILENAME, Integer.valueOf(TOKEN_FILENAME));
 512  0
             addToken(STRING_MODEL, Integer.valueOf(TOKEN_MODEL));
 513  0
         }
 514  
     }
 515  
 
 516  
 }