blob: c38b3ea00d9b7ecd66a6f61c437e7667d39a9718 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 ALL4TEC & CEA LIST.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ALL4TEC & CEA LIST - initial API and implementation
******************************************************************************/
package org.polarsys.esf.core.profile.esfarchitectureconcepts.application;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
import org.eclipse.papyrus.uml.decoratormodel.internal.commands.CreateDecoratorModelCommand;
import org.eclipse.papyrus.uml.decoratormodel.internal.commands.SaveDecoratorModelCommand;
import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.util.UMLUtil;
import org.polarsys.esf.core.profile.esfarchitectureconcepts.set.ESFArchitectureConceptsSet;
import org.polarsys.esf.core.utils.ModelUtil;
import org.polarsys.esf.esfarchitectureconcepts.SDirection;
import org.polarsys.esf.esfarchitectureconcepts.impl.SBlock;
import org.polarsys.esf.esfarchitectureconcepts.impl.SConnector;
import org.polarsys.esf.esfarchitectureconcepts.impl.SModel;
import org.polarsys.esf.esfarchitectureconcepts.impl.SPart;
import org.polarsys.esf.esfarchitectureconcepts.impl.SPort;
/**
* Class responsible of the ESFArchitectureConcepts' annotation application on the model.
*
* @author $Author: ymunoz $
* @version $Revision: 168 $
*/
public final class ApplyESFArchitectureConceptsAnnotation {
/** Label of the command to apply annotation on the UML model. */
private static final String CMD_LABEL_APPLY_ANNOTATION_ON_UML_MODEL = "ApplyESFArchitectureConceptsAnnotation: Apply Annotation on the UML model"; //$NON-NLS-1$
/** Key words for Output port. */
private static final String[] OUTPUT = { "out", "output" }; //$NON-NLS-1$ //$NON-NLS-2$
/** Key words for Input port. */
private static final String[] INPUT = { "in", "input" }; //$NON-NLS-1$ //$NON-NLS-2$
/** Regular expression used to verify if a line contains more than one word. */
private static final String REGEX_MORE_THAN_ONE_WORD = "(\\w)(\\s)(\\w)"; //$NON-NLS-1$
/**
* Default constructor.
*/
private ApplyESFArchitectureConceptsAnnotation() {
}
/**
* Verify if the ESFArchitectureConcepts profile is applied to this model.
*
* @param pModel
* The model
* @return True or false
*/
public static Boolean isProfileApplied(final Model pModel) {
return pModel.isProfileApplied(getProfile(pModel));
}
/**
* Retrieve the ESFArchitectureConcepts profile.
*
* @param pModel
* The model
* @return The ESFArchitectureConcepts profile
*/
public static Profile getProfile(final Model pModel) {
Profile vESFArchiConceptsProfile = (Profile) PackageUtil
.loadPackage(URI.createURI(ESFArchitectureConceptsSet.PROFILE_PATH), pModel.eResource().getResourceSet());
return vESFArchiConceptsProfile;
}
/**
* Apply the ESFArchitectureConcepts profile to this model.
*
* @param pModel
* The model
*/
public static void applyProfile(final Model pModel, final Model userModel, final URI profileAppURI) {
// Retrieve the ESFArchitectureConcepts profile and apply it
Profile vESFArchiConceptsProfile = getProfile(pModel);
if (vESFArchiConceptsProfile != null) {
ResourceSet rs = pModel.eResource().getResourceSet();
Resource decoratorResource = rs.getResource(profileAppURI, false);
org.eclipse.uml2.uml.Package decoratorModel = DecoratorModelUtils.getDecoratorModel(decoratorResource);
// create decorator package on user model in order to trigger the "external profile" application dialog
DecoratorModelUtils.getDecoratorPackage(decoratorModel, userModel, true);
org.eclipse.uml2.uml.Package decoratorPModel = DecoratorModelUtils.getDecoratorPackage(decoratorModel, pModel, true);
PackageUtil.applyProfile(decoratorPModel, vESFArchiConceptsProfile, true);
}
}
/**
* Apply ESFArchitectureConcepts' annotation on the UML model.
*
* @param pModel
* The UML model object {@link Model}
*/
@SuppressWarnings({ "nls", "restriction" })
public static void applyAnnotationOnUMLModel(final Model pModel) {
TransactionalEditingDomain vDomain = ModelUtil.getTransactionalEditingDomain(pModel);
final Model vESFModel = ModelUtil.getWorkingModel();
String newPath = vESFModel.eResource().getURI().toString().replace(".uml", ".profileapp.uml");
final URI profileAppURI = URI.createURI(newPath, false);
RecordingCommand vApplyAnnotationCmd = new RecordingCommand(vDomain, CMD_LABEL_APPLY_ANNOTATION_ON_UML_MODEL) {
/**
* ESFArchitectureConcepts' application annotation on the UML model.
*/
@Override
protected void doExecute() {
if (!isProfileApplied(pModel)) {
applyProfile(pModel, vESFModel, profileAppURI);
}
// Apply the SModel stereotype on the UML model object "Model"
if (UMLUtil.getStereotypeApplication(pModel, SModel.class) == null) {
StereotypeUtil.apply(pModel, SModel.class);
}
// Walk through the Model and apply the ESFArchitectureConcepts' annotation
walkThroughModelAndApplyAnnotation(pModel);
}
};
try {
// Command cmd = DecoratorModelUtils.createSeparateProfileApplicationsCommand(profileApplications, URI.createFileURI(newPath), pModel.getName());
CreateDecoratorModelCommand cmd = new CreateDecoratorModelCommand(vDomain, profileAppURI, vESFModel.getName());
vDomain.getCommandStack().execute(cmd);
vDomain.getCommandStack().execute(vApplyAnnotationCmd);
ReadOnlyManager.getReadOnlyHandler(vDomain).makeWritable(ReadOnlyAxis.anyAxis(), pModel);
if (vDomain.getResourceSet() instanceof ModelSet) {
SaveDecoratorModelCommand saveCmd = new SaveDecoratorModelCommand((ModelSet) vDomain.getResourceSet(), profileAppURI);
vDomain.getCommandStack().execute(saveCmd);
}
}
catch (final IllegalArgumentException pException) {
ESFArchitectureConceptsProfileApplicationActivator.logError(
"Error during the application of the ESFArchitectureConcepts annotation on the model", //$NON-NLS-1$
pException);
}
}
/**
* Walk the Model and apply the ESFArchitectureConcepts' annotation.
*
* @param pModel
* the UML model object {@link Model}
*/
private static void walkThroughModelAndApplyAnnotation(final Model pModel) {
for (Element vElement : pModel.allOwnedElements()) {
// Apply the SBlock stereotype on the UML model object "Class"
if ((vElement instanceof Class) && (UMLUtil.getStereotypeApplication(vElement, SBlock.class) == null)) {
StereotypeUtil.apply(vElement, SBlock.class);
// Apply the SPort stereotype on the UML model object "Port"
} else if ((vElement instanceof Port)
&& (UMLUtil.getStereotypeApplication(vElement, SPort.class) == null)) {
Port vPort = (Port) vElement;
SPort vSPort = StereotypeUtil.applyApp(vPort, SPort.class);
SDirection vPortDirection = findPortDirection(vPort);
// If the port direction is not default direction
if (SDirection.INOUT != vPortDirection) {
// Set the port direction
vSPort.setSDirection(vPortDirection);
}
// Apply the SConnector stereotype on the UML model object "Connector"
} else if ((vElement instanceof Connector)
&& (UMLUtil.getStereotypeApplication(vElement, SConnector.class) == null)) {
StereotypeUtil.apply(vElement, SConnector.class);
// Apply the SPart stereotype on the UML model object "Property" typed by a Class
} else if ((vElement instanceof Property)
&& (UMLUtil.getStereotypeApplication(vElement, SPart.class) == null)) {
Type vType = ((Property) vElement).getType();
if ((vType != null) && (vType instanceof Class)) {
StereotypeUtil.apply(vElement, SPart.class);
}
}
}
}
/**
* Find port direction from comments.
*
* @param pPort
* The UML model object {@link Port}
* @return The SDirection
*/
private static SDirection findPortDirection(final Port pPort) {
List<Comment> vCommentsList = pPort.getOwnedComments();
SDirection vSDirection = SDirection.INOUT;
Iterator<Comment> vIterator = vCommentsList.iterator();
while (SDirection.INOUT == vSDirection && vIterator.hasNext()) {
Comment vComment = vIterator.next();
String vBody = vComment.getBody();
Pattern vMoreThanOneWord = Pattern.compile(REGEX_MORE_THAN_ONE_WORD);
Matcher vMatcher = vMoreThanOneWord.matcher(vBody);
// Verify if the first line of the comment contains the only one word
if (!vMatcher.find()) {
boolean vFind = false;
int vIndex = 0;
// Verify if the comment contains "in" or "input" substring
while ((!vFind) && (INPUT.length > vIndex)) {
String vInput = INPUT[vIndex];
if (vBody.toLowerCase().contains(vInput)) {
vSDirection = SDirection.IN;
vFind = true;
}
vIndex++;
}
if (vSDirection.equals(SDirection.INOUT)) {
vIndex = 0;
// Verify if the comment contains "out" or "output" substring
while ((!vFind) && (OUTPUT.length > vIndex)) {
String vOutput = OUTPUT[vIndex];
if (vBody.toLowerCase().contains(vOutput)) {
vSDirection = SDirection.OUT;
vFind = true;
}
vIndex++;
}
}
}
}
return vSDirection;
}
}