blob: 2476bd7df086145763c52e4a7bed73d990346a32 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 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
* Martin Fleck - bug 515041
*******************************************************************************/
package org.eclipse.emf.compare.uml2.papyrus.internal.hook.migration;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* This class is a reflective facade for the ProfileNamespaceURIPattern API provided in Papyrus for profile
* migration. In order to also support the automatic profile migration in EMF Compare for Eclipse Luna and
* upwards and to allow the code to compile, we need to call the Papyrus API reflectively.
*
* @author Martin Fleck <mfleck@eclipsesource.com>
*/
public final class ProfileNamespaceURIPatternAPI {
/**
* Fully qualified name of the ProfileNamespaceURIPatternRegistry class.
*/
private static final String REGISTRY_CLASS = "org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternRegistry"; //$NON-NLS-1$
/**
* Name of the instance field of the ProfileNamespaceURIPatternRegistry class.
*/
private static final String REGISTRY_FIELD_INSTANCE = "INSTANCE"; //$NON-NLS-1$
/**
* Name of the register method of the ProfileNamespaceURIPatternRegistry class.
*/
private static final String REGISTRY_METHOD_REGISTER = "register"; //$NON-NLS-1$
/**
* Name of the unregister method of the ProfileNamespaceURIPatternRegistry class.
*/
private static final String REGISTRY_METHOD_UNREGISTER = "unregister"; //$NON-NLS-1$
/**
* Name of the tryFindComparison method of the ProfileNamespaceURIPatternRegistry class.
*/
private static final String REGISTRY_METHOD_TRY_FIND_COMPARISON = "tryFindComparison"; //$NON-NLS-1$
/**
* Fully qualified name of the ProfileNamespaceURIPattern class.
*/
private static final String PATTERN_CLASS = "org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPattern"; //$NON-NLS-1$
/**
* Fully qualified name of the ProfileNamespaceURIPatternComparison class.
*/
private static final String COMPARISON_CLASS = "org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternComparison"; //$NON-NLS-1$
/**
* Name of the isEqualVersionlessNamespaceURI method of the ProfileNamespaceURIPatternComparison class.
*/
private static final String COMPARISON_METHOD_IS_EQUAL_VERSIONLESS_NAMESPACE_URI = "isEqualVersionlessNamespaceURI"; //$NON-NLS-1$
/**
* Name of the isPresent method of the Optional class from Guava.
*/
private static final String OPTIONAL_METHOD_IS_PRESENT = "isPresent"; //$NON-NLS-1$
/**
* Name of the get method of the Optional class from Guava.
*/
private static final String OPTIONAL_METHOD_GET = "get"; //$NON-NLS-1$
/**
* ProfileNamespaceURIPatternRegistry singleton instance.
*/
private static Object registryInstance;
/**
* Register method of the ProfileNamespaceURIPatternRegistry class.
*/
private static Method registryRegisterMethod;
/**
* Unregister method of the ProfileNamespaceURIPatternRegistry class.
*/
private static Method registryUnregisterMethod;
/**
* TryFindComparison method of the ProfileNamespaceURIPatternRegistry class.
*/
private static Method registryTryFindComparisonMethod;
/**
* ProfileNamespaceURIPattern class.
*/
private static Class<?> patternClass;
/**
* IsEqualVersionlessNamespaceURI method of the ProfileNamespaceURIPatternComparison class.
*/
private static Method comparisonIsEqualVersionlessNamespaceURIMethod;
static {
try {
final Class<?> registryClass = Class.forName(REGISTRY_CLASS);
patternClass = Class.forName(PATTERN_CLASS);
final Class<?> comparisonClass = Class.forName(COMPARISON_CLASS);
final Field registryInstanceField = registryClass.getField(REGISTRY_FIELD_INSTANCE);
registryInstance = registryInstanceField.get(null);
registryTryFindComparisonMethod = registryClass.getMethod(REGISTRY_METHOD_TRY_FIND_COMPARISON,
String.class, String.class);
registryRegisterMethod = registryClass.getMethod(REGISTRY_METHOD_REGISTER, patternClass);
registryUnregisterMethod = registryClass.getMethod(REGISTRY_METHOD_UNREGISTER, patternClass);
comparisonIsEqualVersionlessNamespaceURIMethod = comparisonClass
.getMethod(COMPARISON_METHOD_IS_EQUAL_VERSIONLESS_NAMESPACE_URI);
} catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException | NoSuchMethodException e) {
// do nothing
}
}
/**
* Hide default constructor in utility class.
*/
private ProfileNamespaceURIPatternAPI() {
}
/**
* Silently failing method for calling a method. Any exception thrown through the invocation of the method
* are silently ignored.
*
* @param method
* the method to be invoked
* @param object
* the object the underlying method is invoked from
* @param args
* the arguments used for the method call
* @return result of the method call or null if the method invocation has failed
*/
protected static Object callMethod(Method method, Object object, Object... args) {
try {
return method.invoke(object, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// do nothing
}
return null;
}
/**
* Returns true if the ProfileNamespaceURIPattern API is available, false otherwise.
*
* @return true if the ProfileNamespaceURIPattern API is available, false otherwise.
*/
public static boolean isAvailable() {
// check if last assigned field is available
return comparisonIsEqualVersionlessNamespaceURIMethod != null;
}
/**
* Reflectively creates a new profile namespace URI pattern with the given namespace URI pattern. The URI
* pattern is a Regex that can split namespace URIs into the profile-identifying part (without version)
* and the versioning part. The created pattern uses the default versioning formatting producing a
* comma-separated version string.
*
* @param pattern
* pattern used to split the namespace URI
* @return newly created pattern object or null if the API is not available
*/
public static Object createPattern(String pattern) {
if (!isAvailable()) {
return null; // avoid error preemptively
}
Object patternObject = null;
try {
Constructor<?> patternConstructor = patternClass.getConstructor(String.class);
patternObject = patternConstructor.newInstance(pattern);
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
// do nothing
}
return patternObject;
}
/**
* Reflectively adds the provided profile namespace URI pattern to the registry.
*
* @param profileNamespaceURIPattern
* pattern to be registered
*/
public static void registerPattern(Object profileNamespaceURIPattern) {
if (!isAvailable() || profileNamespaceURIPattern == null) {
return; // avoid error preemptively
}
callMethod(registryRegisterMethod, registryInstance, profileNamespaceURIPattern);
}
/**
* Reflectively removes the given profile namespace URI patterns from the registry. If the pattern can not
* be found, the registry remains unchanged.
*
* @param profileNamespaceURIPattern
* pattern to be unregistered, if present
*/
public static void unregisterPattern(Object profileNamespaceURIPattern) {
if (!isAvailable() || profileNamespaceURIPattern == null) {
return; // avoid error preemptively
}
callMethod(registryUnregisterMethod, registryInstance, profileNamespaceURIPattern);
}
/**
* Reflectively uses the Profile Namespace URI Pattern mechanism to determine whether the two provided
* namespace URIs are the same not considering versioning information in the URI. This method only returns
* true if both URIs match a pattern and their comparison is valid.
*
* @param lhsNamespaceUri
* left-hand side namespace URI of the comparison
* @param rhsNamespaceUri
* right-hand side namespace URI of the comparison
* @return true if the two namespace URIs can be compared and refer to the same versionless URI, false
* otherwise
*/
public static boolean isEqualVersionlessNamespaceURI(String lhsNamespaceUri, String rhsNamespaceUri) {
if (!isAvailable()) {
return false; // avoid error preemptively
}
Object optionalComparison = callMethod(registryTryFindComparisonMethod, registryInstance,
lhsNamespaceUri, rhsNamespaceUri);
if (optionalComparison == null) {
return false;
}
// use reflection to query result due to potentially incompatible Guava versions, cf. bug 515041
try {
Method isPresentMethod = optionalComparison.getClass().getMethod(OPTIONAL_METHOD_IS_PRESENT);
isPresentMethod.setAccessible(true);
Object isPresent = isPresentMethod.invoke(optionalComparison);
if (isPresent != null && Boolean.parseBoolean(isPresent.toString())) {
Method getMethod = optionalComparison.getClass().getMethod(OPTIONAL_METHOD_GET);
getMethod.setAccessible(true);
Object comparison = getMethod.invoke(optionalComparison);
if (comparison != null) {
Object isEqual = callMethod(comparisonIsEqualVersionlessNamespaceURIMethod, comparison);
return isEqual != null && new Boolean(isEqual.toString()).booleanValue();
}
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// do nothing
}
return false;
}
}