Coverage Report - org.argouml.profile.internal.ProfileManagerImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ProfileManagerImpl
46%
85/182
33%
35/104
3.708
ProfileManagerImpl$1
8%
1/12
0%
0/4
3.708
 
 1  
 /* $Id: ProfileManagerImpl.java 18321 2010-04-21 19:13:43Z bobtarling $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009-2010 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  
  *    euluis
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2007 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.profile.internal;
 40  
 
 41  
 import java.io.File;
 42  
 import java.net.URI;
 43  
 import java.net.URISyntaxException;
 44  
 import java.util.ArrayList;
 45  
 import java.util.Collection;
 46  
 import java.util.Collections;
 47  
 import java.util.List;
 48  
 import java.util.StringTokenizer;
 49  
 
 50  
 import org.apache.log4j.Logger;
 51  
 import org.argouml.cognitive.Agency;
 52  
 import org.argouml.cognitive.Critic;
 53  
 import org.argouml.configuration.Configuration;
 54  
 import org.argouml.configuration.ConfigurationKey;
 55  
 import org.argouml.kernel.ProfileConfiguration;
 56  
 import org.argouml.model.Model;
 57  
 import org.argouml.model.UmlException;
 58  
 import org.argouml.profile.Profile;
 59  
 import org.argouml.profile.ProfileException;
 60  
 import org.argouml.profile.ProfileManager;
 61  
 import org.argouml.profile.UserDefinedProfile;
 62  
 import org.argouml.profile.UserDefinedProfileHelper;
 63  
 import org.argouml.uml.cognitive.critics.ProfileCodeGeneration;
 64  
 import org.argouml.uml.cognitive.critics.ProfileGoodPractices;
 65  
 
 66  
 /**
 67  
  * Default <code>ProfileManager</code> implementation
 68  
  *
 69  
  * @author Marcos Aurelio
 70  
  */
 71  900
 public class ProfileManagerImpl implements ProfileManager {
 72  
     
 73  900
     private static final Logger LOG = Logger.getLogger(
 74  
             ProfileManagerImpl.class);
 75  
 
 76  
     private static final String DIRECTORY_SEPARATOR = "*";
 77  
 
 78  
     /**
 79  
      * The configuration key for the default profiles.
 80  
      */
 81  900
     public static final ConfigurationKey KEY_DEFAULT_PROFILES = Configuration
 82  
             .makeKey("profiles", "default");
 83  
 
 84  
     /**
 85  
      * The configuration key for the search directories.
 86  
      */
 87  900
     public static final ConfigurationKey KEY_DEFAULT_DIRECTORIES = Configuration
 88  
             .makeKey("profiles", "directories");
 89  
 
 90  
     /**
 91  
      * Avoids recursive configuration update when loading configuration
 92  
      */
 93  900
     private boolean disableConfigurationUpdate = false;
 94  
     
 95  900
     private List<Profile> profiles = new ArrayList<Profile>();
 96  
 
 97  900
     private List<Profile> defaultProfiles = new ArrayList<Profile>();
 98  
 
 99  900
     private List<String> searchDirectories = new ArrayList<String>();
 100  
 
 101  
     private ProfileUML profileUML;
 102  
     
 103  
     private ProfileGoodPractices profileGoodPractices;
 104  
     
 105  
     private ProfileCodeGeneration profileCodeGeneration;
 106  
 
 107  
     private DependencyResolver<File> resolver;
 108  
 
 109  
     /**
 110  
      * Constructor - includes initialization of built-in default profiles.
 111  
      */
 112  900
     public ProfileManagerImpl() {
 113  
         try {
 114  900
             disableConfigurationUpdate = true;
 115  
             
 116  900
             profileUML = new ProfileUML();
 117  900
             profileGoodPractices = new ProfileGoodPractices();
 118  900
             profileCodeGeneration = new ProfileCodeGeneration(
 119  
                     profileGoodPractices);
 120  
             
 121  900
             registerProfileInternal(profileUML);
 122  900
             addToDefaultProfiles(profileUML); 
 123  
                 // the UML Profile is always present and default
 124  
             
 125  
             // register the built-in profiles
 126  900
             registerProfileInternal(profileGoodPractices);
 127  900
             registerProfileInternal(profileCodeGeneration);
 128  900
             registerProfileInternal(new ProfileMeta());
 129  
 
 130  0
         } catch (ProfileException e) {
 131  
             // TODO: Why is this throwing a generic runtime exception?!?!
 132  0
             throw new RuntimeException(e);
 133  
         } finally {
 134  900
             disableConfigurationUpdate = false;
 135  900
         }
 136  900
         createUserDefinedProfilesDependencyResolver();
 137  900
         loadDirectoriesFromConfiguration();
 138  900
         refreshRegisteredProfiles();
 139  900
         loadDefaultProfilesfromConfiguration();
 140  900
     }
 141  
 
 142  
     private void createUserDefinedProfilesDependencyResolver() {
 143  900
         final ProfileManager profileManager = this;
 144  900
         DependencyChecker<File> checker = new DependencyChecker<File>() {
 145  
             public boolean check(File file) {
 146  0
                 boolean found = findUserDefinedProfile(file) != null;
 147  0
                 if (!found) {
 148  0
                     UserDefinedProfile udp = null;
 149  
                     try {
 150  0
                         udp = new UserDefinedProfile(file, profileManager);
 151  0
                         registerProfileInternal(udp);
 152  0
                         found = true;
 153  0
                         LOG.debug("UserDefinedProfile for file "
 154  
                             + file.getAbsolutePath() + " registered.");
 155  0
                     } catch (ProfileException e) {
 156  
                         // if an exception is raised file is unusable
 157  0
                         LOG.info("Failed to load user defined profile "
 158  
                             + file.getAbsolutePath() + ".", e);
 159  0
                     }
 160  
                 }
 161  0
                 return found;
 162  
             }
 163  
         };
 164  900
         resolver = new DependencyResolver<File>(checker);
 165  900
     }
 166  
 
 167  
     private void loadDefaultProfilesfromConfiguration() {
 168  900
         if (!disableConfigurationUpdate) {
 169  900
             disableConfigurationUpdate = true;
 170  
 
 171  900
             String defaultProfilesList = Configuration
 172  
                     .getString(KEY_DEFAULT_PROFILES);
 173  900
             if (defaultProfilesList.equals("")) {
 174  
                 // if the list does not exist add the code generation and
 175  
                 // good practices profiles as default
 176  900
                 addToDefaultProfiles(profileGoodPractices);
 177  900
                 addToDefaultProfiles(profileCodeGeneration);
 178  
             } else {
 179  0
                 StringTokenizer tokenizer = new StringTokenizer(
 180  
                         defaultProfilesList, DIRECTORY_SEPARATOR, false);
 181  
 
 182  0
                 while (tokenizer.hasMoreTokens()) {
 183  0
                     String desc = tokenizer.nextToken();
 184  0
                     Profile p = null;
 185  
 
 186  0
                     if (desc.charAt(0) == 'U') {
 187  0
                         String fileName = desc.substring(1);
 188  
                         File file;
 189  
                         try {
 190  0
                             file = new File(new URI(fileName));
 191  
 
 192  0
                             p = findUserDefinedProfile(file);
 193  
 
 194  0
                             if (p == null) {
 195  
                                 try {
 196  0
                                     p = new UserDefinedProfile(file, this);
 197  0
                                     registerProfileInternal(p);
 198  0
                                 } catch (ProfileException e) {
 199  0
                                     LOG.error("Error loading profile: " + file,
 200  
                                             e);
 201  0
                                 }
 202  
                             }
 203  0
                         } catch (URISyntaxException e1) {
 204  0
                             LOG.error("Invalid path for Profile: " + fileName,
 205  
                                     e1);
 206  0
                         } catch (Throwable e2) {
 207  0
                             LOG.error("Error loading profile: " + fileName,
 208  
                                     e2);                            
 209  0
                         }
 210  0
                     } else if (desc.charAt(0) == 'C') {
 211  0
                         String profileIdentifier = desc.substring(1);
 212  0
                         p = lookForRegisteredProfile(profileIdentifier);
 213  
                     }
 214  0
                     if (p != null) {
 215  0
                         addToDefaultProfiles(p);
 216  
                     }
 217  0
                 }
 218  
             }
 219  900
             disableConfigurationUpdate = false;
 220  
         }
 221  900
     }
 222  
 
 223  
     private void updateDefaultProfilesConfiguration() {
 224  2700
         if (!disableConfigurationUpdate) {
 225  0
             StringBuffer buf = new StringBuffer();
 226  0
             for (Profile p : defaultProfiles) {
 227  0
                 if (p instanceof UserDefinedProfile) {
 228  0
                     buf.append("U"
 229  
                             + ((UserDefinedProfile) p).getModelFile()
 230  
                                     .toURI().toASCIIString());
 231  
                 } else {
 232  0
                     buf.append("C" + p.getProfileIdentifier());
 233  
                 }
 234  0
                 buf.append(DIRECTORY_SEPARATOR);
 235  
             }
 236  0
             Configuration.setString(KEY_DEFAULT_PROFILES, buf.toString());
 237  
         }
 238  2700
     }
 239  
 
 240  
     private void loadDirectoriesFromConfiguration() {
 241  900
         disableConfigurationUpdate = true;
 242  900
         StringTokenizer tokenizer = 
 243  
             new StringTokenizer(
 244  
                     Configuration.getString(KEY_DEFAULT_DIRECTORIES), 
 245  
                     DIRECTORY_SEPARATOR, false);
 246  900
         while (tokenizer.hasMoreTokens()) {
 247  0
             searchDirectories.add(tokenizer.nextToken());
 248  
         }
 249  900
         disableConfigurationUpdate = false;
 250  900
     }
 251  
 
 252  
     private void updateSearchDirectoriesConfiguration() {
 253  0
         if (!disableConfigurationUpdate) {
 254  0
             StringBuffer buf = new StringBuffer();
 255  0
             for (String s : searchDirectories) {
 256  0
                 buf.append(s).append(DIRECTORY_SEPARATOR);
 257  
             }
 258  0
             Configuration.setString(KEY_DEFAULT_DIRECTORIES, buf.toString());
 259  
         }
 260  0
     }
 261  
 
 262  
     public List<Profile> getRegisteredProfiles() {
 263  1098
         return profiles;
 264  
     }
 265  
 
 266  
     public void registerProfile(Profile p) {
 267  0
         if (registerProfileInternal(p)) {
 268  
             // this profile could have not been loaded when
 269  
             // the default profile configuration 
 270  
             // was loaded at first, so we need to do it again
 271  0
             loadDefaultProfilesfromConfiguration();
 272  
         }
 273  0
         resolver.resolve();
 274  0
     }
 275  
     
 276  
     /**
 277  
      * @param p the profile to register.
 278  
      * @return true if there should be an attempt to load the default profiles
 279  
      * from the configuration.
 280  
      */
 281  
     private boolean registerProfileInternal(Profile p) {
 282  
         
 283  
         try {
 284  3600
             boolean loadDefaultProfilesFromConfiguration = false;
 285  3600
             if (p != null && !profiles.contains(p)) {
 286  3600
                 if (p instanceof UserDefinedProfile
 287  
                         || getProfileForClass(p.getClass().getName()) == null) {
 288  3600
                     loadDefaultProfilesFromConfiguration = true;
 289  3600
                     profiles.add(p);
 290  3600
                     for (Critic critic : p.getCritics()) {
 291  90900
                         for (Object meta : critic.getCriticizedDesignMaterials()) {
 292  91800
                             Agency.register(critic, meta);
 293  
                         }
 294  90900
                         critic.setEnabled(false);
 295  
                     }
 296  
                 }
 297  
             }
 298  3600
             return loadDefaultProfilesFromConfiguration;
 299  0
         } catch (RuntimeException e) {
 300  
             // TODO: Better if we wrap in a ProfileException and throw that
 301  0
             LOG.error("Error registering profile " + p.getDisplayName());
 302  0
             throw e;
 303  
         }
 304  
     }
 305  
 
 306  
     public void removeProfile(Profile p) {
 307  0
         if (p != null && p != profileUML) {
 308  0
             profiles.remove(p);
 309  0
             defaultProfiles.remove(p);
 310  
         }
 311  
         try {
 312  0
             Collection packages = p.getLoadedPackages();
 313  0
             if (packages != null && !packages.isEmpty()) {
 314  
                 // We assume profile is contained in a single extent
 315  0
                 Model.getUmlFactory().deleteExtent(packages.iterator().next());
 316  
             }
 317  0
         } catch (ProfileException e) {
 318  
             // Nothing to delete if we couldn't get the packages
 319  0
         }
 320  0
     }
 321  
 
 322  
     private static final String OLD_PROFILE_PACKAGE = "org.argouml.uml.profile";
 323  
 
 324  
     private static final String NEW_PROFILE_PACKAGE = 
 325  
         "org.argouml.profile.internal";
 326  
     
 327  
     public Profile getProfileForClass(String profileClass) {
 328  3600
         Profile found = null;
 329  
         
 330  
         // If we found an old-style name, update it to the new package name
 331  3600
         if (profileClass != null 
 332  
                 && profileClass.startsWith(OLD_PROFILE_PACKAGE)) {
 333  0
             profileClass = profileClass.replace(OLD_PROFILE_PACKAGE,
 334  
                     NEW_PROFILE_PACKAGE);
 335  
         }
 336  
         
 337  
         // Make sure the names didn't change again
 338  3600
         assert profileUML.getClass().getName().startsWith(NEW_PROFILE_PACKAGE);
 339  
         
 340  3600
         for (Profile p : profiles) {
 341  5400
             if (p.getClass().getName().equals(profileClass)) {
 342  0
                 found = p;
 343  0
                 break;
 344  
             }
 345  
         }
 346  3600
         return found;
 347  
     }
 348  
 
 349  
     public void addToDefaultProfiles(Profile p) {
 350  2700
         if (p != null && profiles.contains(p) 
 351  
                 && !defaultProfiles.contains(p)) {
 352  2700
             defaultProfiles.add(p);
 353  2700
             updateDefaultProfilesConfiguration();
 354  
         }
 355  2700
     }
 356  
 
 357  
     public List<Profile> getDefaultProfiles() {
 358  1030
         return Collections.unmodifiableList(defaultProfiles);
 359  
     }
 360  
 
 361  
     public void removeFromDefaultProfiles(Profile p) {
 362  0
         if (p != null && p != profileUML && profiles.contains(p)) {
 363  0
             defaultProfiles.remove(p);
 364  0
             updateDefaultProfilesConfiguration();
 365  
         }
 366  0
     }
 367  
 
 368  
     public void addSearchPathDirectory(String path) {
 369  0
         if (path != null && !searchDirectories.contains(path)) {
 370  0
             searchDirectories.add(path);
 371  0
             updateSearchDirectoriesConfiguration();
 372  
             try {
 373  0
                 Model.getXmiReader().addSearchPath(path);
 374  0
             } catch (UmlException e) {
 375  0
                 LOG.error("Couldn't retrive XMI Reader from Model.", e);
 376  0
             }
 377  
         }
 378  0
     }
 379  
 
 380  
     public List<String> getSearchPathDirectories() {
 381  38
         return Collections.unmodifiableList(searchDirectories);
 382  
     }
 383  
 
 384  
     public void removeSearchPathDirectory(String path) {
 385  0
         if (path != null) {
 386  0
             searchDirectories.remove(path);
 387  0
             updateSearchDirectoriesConfiguration();
 388  
             try {
 389  0
                 Model.getXmiReader().removeSearchPath(path);
 390  0
             } catch (UmlException e) {
 391  0
                 LOG.error("Couldn't retrive XMI Reader from Model.", e);
 392  0
             }
 393  
         }
 394  0
     }
 395  
 
 396  
     public void refreshRegisteredProfiles() {
 397  900
         ArrayList<File> dirs = new ArrayList<File>();
 398  900
         for (String dirName : searchDirectories) {
 399  0
             File dir = new File(dirName);
 400  0
             if (dir.exists()) {
 401  0
                 dirs.add(dir);
 402  
             }
 403  0
         }
 404  900
         if (!dirs.isEmpty()) {
 405  
             // TODO: Allow .zargo as profile as well?
 406  0
             List<File> profileFiles = UserDefinedProfileHelper.getFileList(
 407  
                 dirs.toArray(new File[0]));
 408  0
             loadProfiles(profileFiles);
 409  
         }
 410  900
     }
 411  
 
 412  
     void loadProfiles(List<File> profileFiles) {
 413  0
         resolver.resolve(profileFiles);
 414  0
     }
 415  
 
 416  
     private Profile findUserDefinedProfile(File file) {
 417  0
         for (Profile p : profiles) {
 418  0
             if (p instanceof UserDefinedProfile) {
 419  0
                 UserDefinedProfile udp = (UserDefinedProfile) p;
 420  0
                 if (file.equals(udp.getModelFile())) {
 421  0
                     return udp;
 422  
                 }
 423  0
             }
 424  
         }
 425  0
         return null;
 426  
     }
 427  
 
 428  
     public Profile getUMLProfile() {
 429  0
         return profileUML;
 430  
     }
 431  
 
 432  
     /*
 433  
      * @see org.argouml.profile.ProfileManager#lookForRegisteredProfile(java.lang.String)
 434  
      */
 435  
     public Profile lookForRegisteredProfile(String value) {
 436  954
         if (value != null) {
 437  954
             List<Profile> registeredProfiles = getRegisteredProfiles();
 438  954
             for (Profile profile : registeredProfiles) {
 439  1908
                 if (value.equalsIgnoreCase(profile.getProfileIdentifier())) {
 440  954
                     return profile;
 441  
                 }
 442  
             }
 443  
         }
 444  0
         return null;
 445  
     }
 446  
 
 447  
     /*
 448  
      * @param pc
 449  
      * @see org.argouml.profile.ProfileManager#applyConfiguration(org.argouml.kernel.ProfileConfiguration)
 450  
      */
 451  
     public void applyConfiguration(ProfileConfiguration pc) {
 452  980
         for (Profile p : this.profiles) {
 453  3920
             for (Critic c : p.getCritics()) {
 454  98980
                 c.setEnabled(false);
 455  98980
                 Configuration.setBoolean(c.getCriticKey(), false);
 456  
             }
 457  
         }
 458  980
         for (Profile p : pc.getProfiles()) {
 459  2898
             for (Critic c : p.getCritics()) {
 460  94668
                 c.setEnabled(true);
 461  94668
                 Configuration.setBoolean(c.getCriticKey(), true);
 462  
             }
 463  
         }        
 464  980
     }
 465  
 }