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