blob: 3ce5ca7fb7405d7f07f713dd1a955eaac8aea8ef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 EclipseSource Services GmbH and others.
* 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:
* Martin Fleck - initial API and implementation
* Stefan Dirix - bug 498583
* Laurent Delaigue - bug 498583
*******************************************************************************/
package org.eclipse.emf.compare.uml2.papyrus.internal.hook.migration;
import com.google.common.base.Function;
import java.lang.reflect.Field;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.compare.uml2.papyrus.internal.UMLPapyrusCompareMessages;
import org.eclipse.emf.compare.uml2.papyrus.internal.UMLPapyrusComparePlugin;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeApplicationRepairSnippet;
import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.ZombieStereotypesDescriptor;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.UMLPackage;
/**
* Analyzer to retrieve zombie and orphan stereotype applications. Zombies are stereotype applications for
* which the defining {@link EPackage} could not be found. Orphans are stereotype applications for which the
* referenced base element is missing. The implementation of this class is based on the Papyrus' model repair
* capabilities.
*
* @author Martin Fleck <mfleck@eclipsesource.com>
*/
@SuppressWarnings("restriction")
public class StereotypeApplicationRepair extends StereotypeApplicationRepairSnippet {
/**
* The resource under repair.
*/
private Resource resource;
/**
* Creates a new repair analyzer for zombie and orphan stereotype applications for the given resource.
*
* @param resource
* the resource under repair
*/
public StereotypeApplicationRepair(Resource resource) {
// new constructor to provide our own profile supplier
super();
this.resource = resource;
setLabelProviderService(createLabelProviderService());
setProfileSupplier(createProfileSupplier());
}
@Override
public void dispose(ModelSet modelsManager) {
try {
LabelProviderService s = (LabelProviderService)getSuperField("labelProviderService"); //$NON-NLS-1$
if (s != null) {
s.disposeService();
}
} catch (ServiceException ex) {
UMLPapyrusComparePlugin.getDefault().getLog()
.log(new Status(IStatus.WARNING, UMLPapyrusComparePlugin.PLUGIN_ID,
"Unable to dispose Label Provider Service", //$NON-NLS-1$
ex));
}
super.dispose(modelsManager);
}
/**
* Reflectively sets the field with the given name in the super class to the specified fieldValue.
*
* @param fieldName
* name of the field in the super class
* @param fieldValue
* new value of the field in the super class
*/
protected void setSuperField(String fieldName, Object fieldValue) {
try {
final Field superField = getClass().getSuperclass().getDeclaredField(fieldName);
superField.setAccessible(true);
superField.set(this, fieldValue);
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* Reflectively returns the value of field with the given name from the super class. If no such field can
* be found or an exception is thrown, null is returned.
*
* @param fieldName
* name of the field in the super class
* @return field value or null
*/
protected Object getSuperField(String fieldName) {
try {
final Field superField = getClass().getSuperclass().getDeclaredField(fieldName);
superField.setAccessible(true);
return superField.get(this);
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* Reflectively sets the adapter for this repair snippet. This is needed for Eclipse Luna as it expects a
* ModelSet as resource set for the migrated resource.
*
* @param resourceSet
* resource set containing the resource under repair
*/
private void setAdapter(ModelSet resourceSet) {
// adapter needed to provide EPackage.Registry via the adapters resourceSet
final Object adapterObject = getSuperField("adapter"); //$NON-NLS-1$
if (adapterObject instanceof Adapter.Internal) {
((Adapter.Internal)adapterObject).setTarget(resourceSet);
}
}
/**
* Reflectively sets the labelProviderService for this repair snippet. This label provider service is not
* used during the comparison, but necessary for Papyrus which displays a user dialog during the
* migration. The Papyrus label provider needs the Workbench to be initialized, therefore we should use a
* simpler label provider to avoid this requirement.
*
* @param labelProviderService
* label provider service
*/
private void setLabelProviderService(LabelProviderService labelProviderService) {
setSuperField("labelProviderService", labelProviderService); //$NON-NLS-1$
}
/**
* Reflectively sets the profileSupplier for this repair snippet.
*
* @param profileSupplier
* supplier of profiles for missing packages.
*/
protected void setProfileSupplier(Function<EPackage, Profile> profileSupplier) {
setSuperField("dynamicProfileSupplier", profileSupplier); //$NON-NLS-1$
}
/**
* Creates a new label provider service that is used during the migration. In automatic migration, this
* label provider service is not used.
*
* @return newly created label provider service
*/
protected LabelProviderService createLabelProviderService() {
// we use a label provider service that does not need any special UI capabilities
UMLLabelProviderService umlLabelProviderService = new UMLLabelProviderService();
try {
umlLabelProviderService.startService();
} catch (ServiceException ex) {
UMLPapyrusComparePlugin.getDefault().getLog()
.log(new Status(IStatus.WARNING, UMLPapyrusComparePlugin.PLUGIN_ID,
"Unable to start UML Label Provider Service", //$NON-NLS-1$
ex));
}
return umlLabelProviderService;
}
/***
* Creates a new profile supplier that is called if a package is missing and we need to find a profile
* that defines such a package.
*
* @return newly created profile supplier
*/
protected Function<EPackage, Profile> createProfileSupplier() {
return new MissingProfileSupplier(getRootElement(resource));
}
/**
* Returns the resource under analysis.
*
* @return resource
*/
public Resource getResource() {
return resource;
}
/**
* Creates a {@link ModelSet} wrapper around the given resource set to be used for profile migration
* within Eclipse Luna.
*
* @param resourceSet
* resource set containing the resource under repair
* @return newly created model set wrapper
*/
protected ModelSet createModelSetWrapper(ResourceSet resourceSet) {
final ModelSetWrapper modelSet = new ModelSetWrapper(resourceSet);
// avoid read-only for our resource
modelSet.setReadOnly(resource, Boolean.FALSE);
return modelSet;
}
/**
* Analyzes the stereotype applications of the given resources root element and returns a descriptor
* containing zombie and orphan stereotype applications. For zombies, the defining package could not be
* found and for orphans the base element could not be found. The descriptor also already suggests repair
* actions, i.e., migrating the missing package for zombies if possible and deleting the stereotype
* application for orphans.
*
* @return descriptor of zombie and orphan stereotypes
*/
public ZombieStereotypesDescriptor repair() {
try {
final ResourceSet resourceSet = resource.getResourceSet();
final ModelSet modelSet = createModelSetWrapper(resourceSet);
setAdapter(modelSet);
modelSet.getResources().add(resource);
final ZombieStereotypesDescriptor stereotypesDescriptor = getZombieStereotypes(resource);
resourceSet.getResources().add(resource);
return stereotypesDescriptor;
// CHECKSTYLE:OFF
} catch (Exception e) {
// CHECKSTYLE:ON
resource.getErrors().add(new ProfileMigrationDiagnostic(
UMLPapyrusCompareMessages.getString("profile.migration.exception", e, resource))); //$NON-NLS-1$
UMLPapyrusComparePlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, UMLPapyrusComparePlugin.PLUGIN_ID,
"Exception occurred during profile migration", //$NON-NLS-1$
e)); // The exception stack trace will appear in the error log
}
return null;
}
/**
* Returns the root {@link Element element} in the given resource. If multiple elements are present the
* first one is returned.
*
* @param resource
* resource to check
* @return The first root element or null if no element is found
*/
protected static Element getRootElement(Resource resource) {
return (Element)EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.ELEMENT);
}
}