Java tutorial
/******************************************************************************* * Copyright (c) 2010-2015, Abel Hegedus, Istvan Rath and Daniel Varro * 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: * Abel Hegedus - initial API and implementation *******************************************************************************/ package org.eclipse.viatra.addon.validation.runtime; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.viatra.addon.validation.core.api.IConstraintSpecification; import org.eclipse.viatra.query.runtime.matchers.util.IProvider; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; /** * The constraint extension registry is singleton utility for * accessing the constraint specifications registered through extensions * (see VIATRA @Constraint annotation) * * @author Abel Hegedus * */ public class ConstraintExtensionRegistry { private static final String WILDCARD_EDITOR_ID = "*"; private static final String CONSTRAINT_ATTRIBUTE_NAME = "constraint"; private static final String VALIDATION_RUNTIME_CONSTRAINT_EXTENSION_ID = "org.eclipse.viatra.addon.validation.runtime.constraint"; private static final String EDITOR_ID_ATTRIBUTE_NAME = "editorId"; private static final String ENABLED_FOR_EDITOR_ATTRIBUTE_NAME = "enabledForEditor"; private static final String CLASS_ATTRIBUTE_NAME = "class"; static Set<String> genericEditorIds = Sets.newHashSet( "org.eclipse.emf.ecore.presentation.XMLReflectiveEditorID", "org.eclipse.emf.ecore.presentation.ReflectiveEditorID", "org.eclipse.emf.genericEditor"); private static Multimap<String, IProvider<IConstraintSpecification>> editorConstraintSpecificationMap; /** * Constructor hidden for utility class */ private ConstraintExtensionRegistry() { } /** * Returns the map of all the registered constraint specifications for the particular editor Ids. * * @return A Multimap containing all the registered constraint specifications for each editor Id. */ protected static synchronized Multimap<String, IProvider<IConstraintSpecification>> getEditorConstraintSpecificationMap() { if (editorConstraintSpecificationMap == null) { editorConstraintSpecificationMap = loadConstraintSpecificationsFromExtensions(); } return editorConstraintSpecificationMap; } /** * Returns whether there are constraint specifications registered for an editor Id. * * @param editorId * The editor Id which should be checked * @return <code>true</code> if there are registered constraint specifications */ public static synchronized boolean isConstraintSpecificationsRegisteredForEditorId(String editorId) { Multimap<String, IProvider<IConstraintSpecification>> specificationMap = getEditorConstraintSpecificationMap(); if (specificationMap.containsKey(WILDCARD_EDITOR_ID)) { return true; } return specificationMap.containsKey(editorId); } /** * Returns the registered constraint specifications for a particular editor Id. * * @param editorId * The editor Id for which the constraint specifications should be retrieved. * @return The Set of constraint specifications registered. */ public static synchronized Set<IConstraintSpecification> getConstraintSpecificationsForEditorId( String editorId) { if (genericEditorIds.contains(editorId)) { Iterable<IConstraintSpecification> constraintSpecifications = unwrapConstraintSpecifications( getEditorConstraintSpecificationMap().values()); return ImmutableSet.copyOf(constraintSpecifications); } Set<IConstraintSpecification> set = Sets .newHashSet(unwrapConstraintSpecifications(getEditorConstraintSpecificationMap().get(editorId))); Iterables.addAll(set, unwrapConstraintSpecifications(getEditorConstraintSpecificationMap().get(WILDCARD_EDITOR_ID))); return set; } private static Iterable<IConstraintSpecification> unwrapConstraintSpecifications( Collection<IProvider<IConstraintSpecification>> providers) { return providers.stream().filter(Objects::nonNull).map(Supplier::get).collect(Collectors.toList()); } /** * Loads and returns the constraint specifications registered in the available extensions. (constraintspecification * extension point extensions) * * @return A Multimap containing all the registered constraint specifications from the available extension for each * editor Id. */ private static synchronized Multimap<String, IProvider<IConstraintSpecification>> loadConstraintSpecificationsFromExtensions() { Multimap<String, IProvider<IConstraintSpecification>> result = HashMultimap.create(); IExtensionRegistry reg = Platform.getExtensionRegistry(); IExtensionPoint ep = reg.getExtensionPoint(VALIDATION_RUNTIME_CONSTRAINT_EXTENSION_ID); for (IExtension extension : ep.getExtensions()) { for (IConfigurationElement ce : extension.getConfigurationElements()) { if (ce.getName().equals(CONSTRAINT_ATTRIBUTE_NAME)) { processConstraintSpecificationConfigurationElement(result, ce); } } } return result; } /** * Processes the given configuration element: in case if it is an instance of IConstraintSpecification it puts it in * the provided Multimap with the editor Ids it is registered for. * * @param result * The Multimap in which the constraint specification will be placed with it's editorIds. * @param ce * The configuration element to be processed. */ private static void processConstraintSpecificationConfigurationElement( Multimap<String, IProvider<IConstraintSpecification>> result, IConfigurationElement ce) { List<String> ids = new ArrayList<String>(); for (IConfigurationElement child : ce.getChildren()) { if (child.getName().equals(ENABLED_FOR_EDITOR_ATTRIBUTE_NAME)) { String id = child.getAttribute(EDITOR_ID_ATTRIBUTE_NAME); if (id != null && !id.equals("")) { ids.add(id); } } } ConstraintSpecificationProvider constraintSpecificationProvider = new ConstraintSpecificationProvider(ce); if (ids.isEmpty()) { ids.add(WILDCARD_EDITOR_ID); } for (String id : ids) { result.put(id, constraintSpecificationProvider); } } /** * A provider implementation for PQuery instances based on extension elements. It is expected that the getter will only * @author stampie * */ private static final class ConstraintSpecificationProvider implements IProvider<IConstraintSpecification> { private final IConfigurationElement element; private IConstraintSpecification constraintSpecification; public ConstraintSpecificationProvider(IConfigurationElement element) { this.element = element; this.constraintSpecification = null; } @Override public IConstraintSpecification get() { try { if (constraintSpecification == null) { constraintSpecification = (IConstraintSpecification) element .createExecutableExtension(CLASS_ATTRIBUTE_NAME); } return constraintSpecification; } catch (CoreException e) { throw new IllegalArgumentException("Error initializing constraint specification", e); } } } }