| /******************************************************************************* |
| * 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; |
| } |
| } |