BaseProfile.java
/* $Id$
*****************************************************************************
* Copyright (c) 2009-2013 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:
* Luis Sergio Oliveira (euluis)
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// Copyright (c) 2007-2009 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.language.cpp.profile;
import static org.argouml.model.Model.getCoreFactory;
import static org.argouml.model.Model.getCoreHelper;
import static org.argouml.model.Model.getExtensionMechanismsFactory;
import static org.argouml.model.Model.getExtensionMechanismsHelper;
import static org.argouml.model.Model.getFacade;
import static org.argouml.model.Model.getModelManagementHelper;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import org.argouml.profile.ProfileException;
import org.argouml.profile.ProfileModelLoader;
import org.argouml.profile.ProfileReference;
import org.argouml.profile.ResourceModelLoader;
import org.argouml.model.Model;
/**
* <p>A class that facilitates access to the UML profile for C++
* (CppUmlProfile.xmi).
* This is done by facilitating the use of the stereotypes, built-ins
* and other model elements of the profile in the model which is being used.
* </p>
* <p>Both the generator and the importer must use the same profile,
* if not we are going to make future RTE very difficult.
* Also, the users of the module are going to be
* confused.
* The main point in favor of this is that there is no open source UML
* profile for C++.
* Lets be pioneers here ;-)
* </p>
*
* @author Luis Sergio Oliveira (euluis)
* @since 0.25.4
* @see Issue 3771 (http://argouml.tigris.org/issues/show_bug.cgi?id=3771)
*/
public class BaseProfile {
private static final Logger LOG = Logger.getLogger(
BaseProfile.class.getName());
/**
* The name of the documentation Tagged Value.
*/
public static final String TV_NAME_DOCUMENTATION = "documentation";
static final String PROFILE_FILE_NAME =
"/org/argouml/language/cpp/profile/CppUmlProfile.xmi";
static {
URL profileURL = null;
try {
profileURL = new URL(
"http://argouml-cpp.tigris.org/profile/CppUmlProfile.xmi");
} catch (MalformedURLException e) {
LOG.severe("Exception " + e);
}
PROFILE_REFERENCE = new ProfileReference(PROFILE_FILE_NAME,
profileURL);
}
static final ProfileReference PROFILE_REFERENCE;
private Collection<Object> models;
/**
* The C++ UML profile as loaded from CppUmlProfile.xmi.
*/
private Object profile;
/**
* Set of built in types.
*/
private Set builtInTypes;
private void initBuiltInTypes() {
builtInTypes = new HashSet();
Collection allDataTypes = getCoreHelper().getAllDataTypes(profile);
for (Object dt : allDataTypes) {
builtInTypes.add(getFacade().getName(dt));
}
}
/**
* Checks if the given type is a C++ builtin type.
*
* @param typeName name of the type to check
* @return true if typeName is a builtin type, false otherwise
*/
public boolean isBuiltIn(String typeName) {
if (builtInTypes == null) {
initBuiltInTypes();
}
typeName = trimAndEnsureOneSpaceOnlyBetweenTokens(typeName);
return builtInTypes.contains(typeName);
}
static String trimAndEnsureOneSpaceOnlyBetweenTokens(String typeName) {
return typeName.trim().replaceAll("\\s+", " ");
}
/**
* Retrieves the given builtin type model element representation as a
* DataType.
*
* @param typeName name of the type
* @return the model element that models the C++ builtin type
*/
public Object getBuiltIn(String typeName) {
assert isBuiltIn(typeName) : "Must be a C++ built in!";
Object builtinType = findDataType(typeName, profile);
if (builtinType == null) {
builtinType = getCoreFactory().buildDataType(typeName,
models.iterator().next());
}
// copy the documentation from the profile if it exists
Object profileDT = findDataType(typeName, profile);
Object dtDocuTV = getFacade().getTaggedValue(profileDT,
TV_NAME_DOCUMENTATION);
if (dtDocuTV != null) {
Object tdDocumentation = getTagDefinition(TV_NAME_DOCUMENTATION);
Object modelDTDocuTV = getExtensionMechanismsFactory().
buildTaggedValue(tdDocumentation,
new String[] {getFacade().getValueOfTag(dtDocuTV)});
getExtensionMechanismsHelper().addTaggedValue(builtinType,
modelDTDocuTV);
}
return builtinType;
}
public static Collection getModels() {
Collection models = new ArrayList();
for (Object rootModelElement : getFacade().getRootElements()) {
if (getFacade().isAModel(rootModelElement)) {
models.add(rootModelElement);
}
}
return models;
}
public static Collection getEditableModels() {
Collection editableModels = new ArrayList();
for (Object rootModelElement : getFacade().getRootElements()) {
if (getFacade().isAModel(rootModelElement) &&
!getModelManagementHelper().isReadOnly(rootModelElement)) {
editableModels.add(rootModelElement);
}
}
return editableModels;
}
public static Object getTagDefinition(String tdName) {
// look for it in all the models
Collection models = getModels();
for (Object model : models) {
Collection tagDefinitions = getModelManagementHelper().
getAllModelElementsOfKindWithModel(model,
Model.getMetaTypes().getTagDefinition());
for (Object td : tagDefinitions) {
if (tdName.equals(getFacade().getName(td))) {
return td;
}
}
}
// create it in an editable model if one is found
Collection editableModels = getEditableModels();
Iterator it = editableModels.iterator();
if (it.hasNext()) {
return getExtensionMechanismsFactory().buildTagDefinition(tdName,
null, it.next());
}
throw new IllegalStateException("Unable to find an editable model.");
}
static Object findDataType(String typeName, Object model2) {
Collection dataTypes = getCoreHelper().getAllDataTypes(model2);
for (Object dt : dataTypes) {
if (getFacade().getName(dt).equals(typeName)) {
return dt;
}
}
return null;
}
Object getProfile() {
return profile;
}
protected BaseProfile(Collection<Object> theModels) {
this(theModels,loadProfileModels().iterator().next());
}
protected BaseProfile(Collection<Object> theModels, Object profileModel) {
models = theModels;
assert models.size() > 0 :
"There must be at least one user model."; //$NON-NLS-1$
assert profileModel != null :
"The profileModel must be non-null."; //$NON-NLS-1$
profile = profileModel;
}
/**
* @return the Collection containing the profile models.
*/
static Collection loadProfileModels() {
ProfileModelLoader profileModelLoader = new ResourceModelLoader(
BaseProfile.class);
Collection elements;
try {
elements = profileModelLoader.loadModel(PROFILE_REFERENCE);
} catch (ProfileException e) {
throw new RuntimeException(e);
}
return elements;
}
protected Object getCppStereotypeInModel(String stereotypeName) {
Object cppStereotype = null;
for (Object model : models) {
cppStereotype = getStereotype(model, stereotypeName);
if (cppStereotype != null) {
break;
}
}
if (cppStereotype == null) {
cppStereotype = getStereotype(profile, stereotypeName);
}
return cppStereotype;
}
private Object getStereotype(Object aModel, String stereotypeName) {
Collection stereotypes = getExtensionMechanismsHelper().getStereotypes(
aModel);
for (Object stereotype : stereotypes) {
if (stereotypeName.equals(getFacade().getName(stereotype))) {
return stereotype;
}
}
return null;
}
protected Object getTagDefinition(String stereoName, String tdName) {
Object stereo = getCppStereotypeInModel(stereoName);
assertModelElementContainedInModels(stereo);
Collection tagDefinitions = getFacade().getTagDefinitions(stereo);
for (Object tagDefinition : tagDefinitions) {
if (tdName.equals(getFacade().getName(tagDefinition))) {
return tagDefinition;
}
}
return null;
}
public void applyStereotype(String stereoName, Object modelElement) {
assertModelElementContainedInModels(modelElement);
Object stereo = getCppStereotypeInModel(stereoName);
getCoreHelper().addStereotype(modelElement, stereo);
}
@SuppressWarnings("serial")
private void assertModelElementContainedInModels(Object modelElement) {
boolean contained = false;
ArrayList<Object> modelsAndProfile = new ArrayList<Object>(models) {
{ add(profile); }
};
for (Object model : modelsAndProfile) {
contained = model.equals(getFacade().getRoot(modelElement));
if (contained) {
break;
}
}
assert contained : "model element (" + modelElement + ") not contained "
+ "in models.";
}
public void applyTaggedValue(String stereoName, String tdName,
Object me, String tvv) {
assertModelElementContainedInModels(me);
assert getFacade().getStereotypes(me).contains(
getCppStereotypeInModel(stereoName));
Object td = getTagDefinition(stereoName, tdName);
Object tv = getExtensionMechanismsFactory().createTaggedValue();
getExtensionMechanismsHelper().setType(tv, td);
getExtensionMechanismsHelper().setDataValues(tv, new String[] {tvv});
getExtensionMechanismsHelper().addTaggedValue(me, tv);
}
/**
* Applies a newlly created tagged value with value tvv related to the
* tag definition with name tdName to the given model element me.
*
* @param tdName the name of the tag definition for which to create a
* tagged value
* @param me the model element to which to apply the tagged value that will
* be created
* @param tvv the value that will be set in the tagged value
*/
public void applyTaggedValue(String tdName, Object me, String tvv) {
assertModelElementContainedInModels(me);
Object td = getTagDefinition(tdName);
Object tv = getExtensionMechanismsFactory().createTaggedValue();
getExtensionMechanismsHelper().setType(tv, td);
getExtensionMechanismsHelper().setDataValues(tv, new String[] {tvv});
getExtensionMechanismsHelper().addTaggedValue(me, tv);
}
}