Source code
/* $Id: ProfileConfiguration.java 19907 2012-12-30 13:06:01Z closettop_nightlybuild $
*****************************************************************************
* Copyright (c) 2009-2012 Contributors - see below
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* thn
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// Copyright (c) 2007 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies. This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason. IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
package org.argouml.kernel;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.argouml.application.events.ArgoEventPump;
import org.argouml.application.events.ArgoEventTypes;
import org.argouml.application.events.ArgoProfileEvent;
import org.argouml.cognitive.Translator;
import org.argouml.configuration.Configuration;
import org.argouml.configuration.ConfigurationKey;
import org.argouml.model.Model;
import org.argouml.profile.DefaultTypeStrategy;
import org.argouml.profile.FigNodeStrategy;
import org.argouml.profile.FormatingStrategy;
import org.argouml.profile.Profile;
import org.argouml.profile.ProfileException;
import org.argouml.profile.ProfileFacade;
/**
* This class captures represents the unique access point for the
* configurability allowed by the use of profiles.
*
* @author maurelio1234
*/
public class ProfileConfiguration extends AbstractProjectMember {
/**
* Logger.
*/
private static final Logger LOG =
Logger.getLogger(ProfileConfiguration.class.getName());
private FormatingStrategy formatingStrategy;
private DefaultTypeStrategy defaultTypeStrategy;
private List figNodeStrategies = new ArrayList();
private List<Profile> profiles = new ArrayList<Profile>();
private List<Object> profileModels = new ArrayList<Object>();
/**
* The extension used in serialization and returned by {@link #getType()}
*/
public static final String EXTENSION = "profile";
/**
* The configuration key for the default stereotype view.
*/
public static final ConfigurationKey KEY_DEFAULT_STEREOTYPE_VIEW =
Configuration.makeKey("profiles", "stereotypeView");
/**
* The default constructor for this class. Sets the default profiles as
* given by {@link org.argouml.profile.ProfileManager} as the profiles of
* the project.
*
* @param project the project that contains this configuration
*/
public ProfileConfiguration(Project project) {
super(EXTENSION, project);
List c = project.getUserDefinedModelList();
Object m = c.isEmpty() ? null : c.get(0);
if (project.getProjectType() != Project.PROFILE_PROJECT) {
// a profile initially has no applied profiles, we go bottom-up
for (Profile p : ProfileFacade.getManager().getDefaultProfiles()) {
addProfile(p, m);
}
}
updateStrategies();
}
/**
* The constructor for pre-defined profile configurations, such as when a
* project is read from a saved file.
* @param project the project that contains this configuration
* @param configuredProfiles the {@link Profile}s that will be the project
* profiles
*/
public ProfileConfiguration(Project project,
Collection<Profile> configuredProfiles) {
super(EXTENSION, project);
List c = project.getUserDefinedModelList();
Object m = c.isEmpty() ? null : c.get(0);
for (Profile profile : configuredProfiles) {
addProfile(profile, m);
}
updateStrategies();
}
private void updateStrategies() {
for (Profile profile : profiles) {
activateFormatingStrategy(profile);
activateDefaultTypeStrategy(profile);
}
}
/**
* @return the current formating strategy
*/
public FormatingStrategy getFormatingStrategy() {
return formatingStrategy;
}
/**
* @return the current default type strategy
*/
public DefaultTypeStrategy getDefaultTypeStrategy() {
return defaultTypeStrategy;
}
/**
* Updates the current strategy to the strategy provided by the
* passed profile. The profile should have been previously registered.
*
* @param profile the profile providing the current default type strategy
*/
public void activateDefaultTypeStrategy(Profile profile) {
if (profile != null && profile.getDefaultTypeStrategy() != null
&& getProfiles().contains(profile)) {
this.defaultTypeStrategy = profile.getDefaultTypeStrategy();
}
}
/**
* Updates the current strategy to the strategy provided by the
* passed profile. The profile should have been previously registered.
*
* @param profile the profile providing the current formating strategy
*/
public void activateFormatingStrategy(Profile profile) {
if (profile != null && profile.getFormatingStrategy() != null
&& getProfiles().contains(profile)) {
this.formatingStrategy = profile.getFormatingStrategy();
}
}
/**
* @return the list of applied profiles
*/
public List<Profile> getProfiles() {
return profiles;
}
/**
* Applies a new profile to this configuration.
*
* @param p the profile to be applied
* @deprecated for 0.29.2, because since UML2 a profile must be applied to
* a model
*/
@Deprecated
public void addProfile(Profile p) {
addProfile(p, null);
}
/**
* Applies a new profile to this configuration and to the given model (or
* other profile, which could be later a collection).
*
* @param p the profile to be applied
* @param m the model (or profile) to which the profile will be applied
*/
@SuppressWarnings("unchecked")
public void addProfile(Profile p, Object m) {
if (!profiles.contains(p)) {
profiles.add(p);
try {
for (Object profile : p.getProfilePackages()) {
Model.getExtensionMechanismsHelper().applyProfile(
m, profile);
}
profileModels.addAll(p.getProfilePackages());
} catch (ProfileException e) {
LOG.log(Level.WARNING,
"Error retrieving profile's " + p + " packages.",
e);
}
FigNodeStrategy fns = p.getFigureStrategy();
if (fns != null) {
figNodeStrategies.add(fns);
}
for (Profile dependency : p.getDependencies()) {
addProfile(dependency, m);
}
updateStrategies();
ArgoEventPump.fireEvent(new ArgoProfileEvent(
ArgoEventTypes.PROFILE_ADDED, new PropertyChangeEvent(this,
"profile", null, p)));
}
}
/**
* @return the list of models of the currently applied profile.
*/
private List getProfileModels() {
return profileModels;
}
/**
* Removes the passed profile from this configuration.
*
* @param p the profile to be applied
* @deprecated for 0.29.2, because since UML2 a profile must be unapplied
* from a model
*/
@Deprecated
public void removeProfile(Profile p) {
removeProfile(p, null);
}
/**
* Removes the passed profile from the configuration and unapplies it from
* the given model (or other profile, which could be later a collection).
*
* @param p the profile to be removed/unapplied
* @param m the model (or profile) to which the profile will be unapplied
*/
public void removeProfile(Profile p, Object m) {
profiles.remove(p);
try {
for (Object profile : p.getProfilePackages()) {
Model.getExtensionMechanismsHelper().unapplyProfile(m, profile);
}
profileModels.removeAll(p.getProfilePackages());
} catch (ProfileException e) {
LOG.log(Level.SEVERE, "Exception", e);
}
FigNodeStrategy fns = p.getFigureStrategy();
if (fns != null) {
figNodeStrategies.remove(fns);
}
if (formatingStrategy == p.getFormatingStrategy()) {
formatingStrategy = null;
}
List<Profile> markForRemoval = new ArrayList<Profile>();
for (Profile profile : profiles) {
if (profile.getDependencies().contains(p)) {
markForRemoval.add(profile);
}
}
for (Profile profile : markForRemoval) {
removeProfile(profile, m);
}
updateStrategies();
ArgoEventPump.fireEvent(new ArgoProfileEvent(
ArgoEventTypes.PROFILE_REMOVED, new PropertyChangeEvent(this,
"profile", p, null)));
}
private FigNodeStrategy compositeFigNodeStrategy = new FigNodeStrategy() {
public Image getIconForStereotype(Object element) {
Iterator it = figNodeStrategies.iterator();
while (it.hasNext()) {
FigNodeStrategy strat = (FigNodeStrategy) it.next();
Image extra = strat.getIconForStereotype(element);
if (extra != null) {
return extra;
}
}
return null;
}
};
/**
* @return the current FigNodeStrategy
*/
public FigNodeStrategy getFigNodeStrategy() {
return compositeFigNodeStrategy;
}
/**
* @return the extension for this project member
* @see org.argouml.kernel.AbstractProjectMember#getType()
*/
public String getType() {
return EXTENSION;
}
/**
* Objects of this class are always consistent, there's no need
* to repair them.
*
* @return the empty string.
* @see org.argouml.kernel.ProjectMember#repair()
*/
public String repair() {
return "";
}
/**
* @return the "Profile Configuration" string
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return Translator.localize("misc.project.profileconfigurationname");
}
/**
* Find a stereotype with the given name which is applicable to the given
* element.
*
* @param name name of stereotype to look for
* @param element model element to which the stereotype must be applicable
* @return the stereotype or null if none found
*/
public Object findStereotypeForObject(String name, Object element) {
Iterator iter = null;
for (Object model : profileModels) {
iter = Model.getFacade().getOwnedElements(model).iterator();
while (iter.hasNext()) {
Object stereo = iter.next();
if (!Model.getFacade().isAStereotype(stereo)
|| !name.equals(Model.getFacade().getName(stereo))) {
continue;
}
if (Model.getExtensionMechanismsHelper().isValidStereotype(
element, stereo)) {
return stereo;
}
}
}
return null;
}
/**
* Search for the given type in all of the profile models.
*
* @param name name of type to be found
* @return the type or null
*/
public Object findType(String name) {
for (Object model : getProfileModels()) {
Object result = findTypeInModel(name, model);
if (result != null) {
return result;
}
}
return null;
}
/**
* Finds a type in a model by name
*
* FIXME: duplicated from the method with the same name in
* org.argouml.profile.internal.ModelUtils.
*
* @param s the type name
* @param model the model
* @return the type or <code>null</code> if the type has not been found.
*/
public static Object findTypeInModel(String s, Object model) {
if (!Model.getFacade().isANamespace(model)) {
throw new IllegalArgumentException(
"Looking for the classifier " + s
+ " in a non-namespace object of " + model
+ ". A namespace was expected.");
}
Collection allClassifiers =
Model.getModelManagementHelper()
.getAllModelElementsOfKind(model,
Model.getMetaTypes().getClassifier());
Object[] classifiers = allClassifiers.toArray();
Object classifier = null;
for (int i = 0; i < classifiers.length; i++) {
classifier = classifiers[i];
if (Model.getFacade().getName(classifier) != null
&& Model.getFacade().getName(classifier).equals(s)) {
return classifier;
}
}
return null;
}
/**
* Find all the model elements in the configured {@link Profile}s
* of the given meta type.
*
* @param metaType the meta type of the model elements to find
* @return a {@link Collection} containing the model elements that
* are of the given meta type
*/
@SuppressWarnings("unchecked")
public Collection findByMetaType(Object metaType) {
Set elements = new HashSet();
Iterator it = getProfileModels().iterator();
while (it.hasNext()) {
Object model = it.next();
elements.addAll(Model.getModelManagementHelper()
.getAllModelElementsOfKind(model, metaType));
}
return elements;
}
/**
* @param modelElement
* ModelElement for which find possible stereotypes
* @return collection of stereotypes which are valid for the given model
* element.
*/
public Collection findAllStereotypesForModelElement(Object modelElement) {
return Model.getExtensionMechanismsHelper().getAllPossibleStereotypes(
getProfileModels(), modelElement);
}
}
Run 1
The code demonstrates reasonable organization with clear method separation and Javadoc comments, contributing to moderate readability. However, several issues lower the score. There are inconsistent indentation styles in methods like activateFormatingStrategy and compositeFigNodeStrategy, which disrupts visual flow. Some methods, such as addProfile and removeProfile, handle multiple responsibilities—profile list management, model application, event firing—reducing clarity and action granularity. Raw types (List, Iterator, Set, Collection) are used extensively without generics, obscuring intent and type safety. Long conditional expressions and deep loops add nesting complexity. The file also has lengthy license headers that delay code reading. Overall, the code is understandable but would benefit from cleanup, consistent formatting, generic types, and refactoring of multi-purpose methods.
Run 2
The code has clear purpose and Javadoc documentation, with logical organization into methods. However, several readability issues exist: inconsistent indentation in methods like activateFormatingStrategy, use of raw types (List, Iterator) despite the file using generics elsewhere, and unclear variable names (e.g., 'c', 'm', 'p'). Some methods are long and combine multiple actions (addProfile, removeProfile), reducing action granularity. The compositeFigNodeStrategy inner class uses tab indentation inconsistent with the rest of the file. The file header contains extensive copyright text that, while necessary, adds visual noise. Methods like findStereotypeForObject have moderate nesting depth with loops and conditionals. Overall, the code is understandable but would benefit from consistent formatting, better variable names, and refactoring long methods into smaller, focused units.
Run 3
The code has clear intent with descriptive method names and JavaDoc comments. Class structure is logical, grouping related methods. However, several issues reduce readability: inconsistent indentation (tabs vs spaces) in some methods like activateFormatingStrategy and the composite FigNodeStrategy; overly long method bodies (addProfile, removeProfile, findTypeInModel) that combine multiple actions; use of raw types and deprecated methods; redundant null checks in activateFormatingStrategy and activateDefaultTypeStrategy; and duplicated logic between constructors. The file also contains an excessive copyright header that isn't code. Some methods have clean flow, but others, like findStereotypeForObject, have deep nesting. Action granularity varies—some lines do too much (e.g., Method chaining in getIconForStereotype is okay, but addProfile's try-catch with loops is dense). Overall, maintainable but could be improved with refactoring for consistency and simplicity.
Run 1
Code Structure: Responsibilities are separated into constructors, strategy management, profile operations, and lookup methods, though the class mixes several concerns. Nesting: Generally shallow, with moderate nesting in profile addition and stereotype searches; early returns and continue statements help. Clarity of intent: Descriptive method names and Javadocs explain most behavior, but short names such as p, m, c, and s, raw collections, and recursive dependency handling require extra interpretation. Code length: Mostly reasonable methods, but repetitive documentation, duplicated constructor setup, and unnecessarily verbose iterator/array traversal increase length. Action granularity: Statements generally perform one action per line; chained API calls and nested event construction are somewhat dense. Reading flow: Related operations mostly follow a natural order, but inconsistent tab/space indentation, mixed iteration styles, and a strategy field declared midway through the methods interrupt consistency.
Run 2
Code Structure: Methods logically separate profile management, strategy selection, and model queries, though the class combines several responsibilities and places a field midway through its methods. Nesting: Mostly shallow, with moderate nesting in profile addition and stereotype searches. Clarity of intent: Descriptive method names and Javadoc explain most operations; abbreviated variables such as p, m, c, and s, raw collections, and generic Object types reduce clarity. Code length: Generally reasonable, but repetitive constructors, verbose iteration, and duplicated lookup logic add avoidable length. Action granularity: Statements usually perform one action per line; nested event constructors and chained model API calls are denser. Reading flow: Organization is mostly natural, but mixed tabs and spaces, inconsistent iteration styles, and recursive dependency handling require extra attention.
Run 3
Code Structure: Methods logically group profile management, strategy selection, and model searches, though the class mixes several responsibilities and embeds an anonymous strategy among methods. Nesting: Generally shallow, but profile addition and stereotype searching contain moderately nested loops and conditionals. Clarity of intent: Descriptive method names and Javadoc explain most behavior; abbreviated variables such as p, m, c, and s, raw collections, and vague exception logging reduce clarity. Code length: Mostly reasonable, but duplicated constructor logic, verbose iterator patterns, and redundant temporary variables add avoidable length. Action granularity: Statements generally perform one action per line; nested event construction and chained model API calls are harder to scan. Reading flow: Method boundaries and documentation support navigation, but inconsistent tabs and spaces, mixed iteration styles, and recursive dependency handling make the flow less uniform.